How to collect user feedback for Agent Server runs ↗
noOriginal Documentation
Documentation Index#
Fetch the complete documentation index at: https://docs.langchain.com/llms.txt Use this file to discover all available pages before exploring further.
This tutorial shows you how to collect user feedback for Agent Server runs and automatically link them to traces in LangSmith. When creating a run, include the keys in the feedback_keys field of the request body. The response will return a pre-signed URL for each key, which your client can use to collect user feedback for the Agent Server run.
LangSmith uses feedback to continuously improve the implementation of your agent. To learn more about how feedback works in LangSmith, refer to LangSmith feedback.
How it works#
- Create a run and include
feedback_keysin the request body. For example, when callingPOST /threads/{thread_id}/runs/stream, setfeedback_keysin the request body to:["user_liked", "user_disliked"] - The
feedbackobject from the response contains a pre-signed URL for each key. For example, thefeedbackobject is:{ "user_liked": "https://api.smith.langchain.com/api/v1/feedback/tokens/ef19fedf-dcac-4cbb-a59c-00661efd6425", "user_disliked": "https://api.smith.langchain.com/api/v1/feedback/tokens/e952734e-c0a0-417b-a04d-fc2209691ed5" } - Request the returned URL (e.g.
POST /api/v1/feedback/tokens/{token_id}) to associate the feedback key with the trace generated from the Agent Server run. For more details, refer to the LangSmith API reference. - LangSmith associates the submitted feedback with the run using the selected feedback key (e.g.
user_likedoruser_disliked).
Call the streaming run API with feedback_keys#
Create a run and parse the feedback object from the response.
from langgraph_sdk import get_client
client = get_client(url="<DEPLOYMENT_URL>", api_key="<API_KEY>")
thread = await client.threads.create()
thread_id = thread["thread_id"]
feedback_urls = {}
async for event in client.runs.stream(
thread_id,
"agent",
input={
"messages": [
{"role": "user", "content": "Tell me a joke about databases."}
]
},
stream_mode="updates",
feedback_keys=["user_liked", "user_disliked"],
):
if event.event == "feedback":
# Example: {"user_liked": ".../feedback/tokens/<id>", "user_disliked": "..."}
feedback_urls = event.data
print("Feedback URLs:", feedback_urls)
elif event.event == "updates":
print(event.data)
```
<span class="tab-end"></span>
<span class="tab-start" data-tab-title="JavaScript SDK"></span>
```javascript
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: "<DEPLOYMENT_URL>", apiKey: "<API_KEY>" });
const thread = await client.threads.create();
const threadId = thread.thread_id;
let feedbackUrls = {};
const streamResponse = client.runs.stream(threadId, "agent", {
input: {
messages: [{ role: "user", content: "Tell me a joke about databases." }],
},
streamMode: "updates",
feedbackKeys: ["user_liked", "user_disliked"],
});
for await (const event of streamResponse) {
if (event.event === "feedback") {
// Example: { user_liked: ".../feedback/tokens/<id>", user_disliked: "..." }
feedbackUrls = event.data;
console.log("Feedback URLs:", feedbackUrls);
} else if (event.event === "updates") {
console.log(event.data);
}
}
```
<span class="tab-end"></span>
<span class="tab-start" data-tab-title="cURL"></span>
```bash
curl --request POST \
--url "<DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/stream" \
--header "Content-Type: application/json" \
--header "x-api-key: <API_KEY>" \
--data '{
"assistant_id": "agent",
"input": {
"messages": [
{
"role": "user",
"content": "Tell me a joke about databases."
}
]
},
"stream_mode": "updates",
"feedback_keys": ["user_liked", "user_disliked"]
}'
```
<span class="tab-end"></span>
<span class="tab-group-end"></span>
## Handle the streamed `feedback` event
The stream emits a `feedback` event like the following:
```text
event: feedback
data: {"user_liked":"https://api.smith.langchain.com/api/v1/feedback/tokens/ef19fedf-dcac-4cbb-a59c-00661efd6425", "user_disliked": "https://api.smith.langchain.com/api/v1/feedback/tokens/e952734e-c0a0-417b-a04d-fc2209691ed5"}Each key in data matches one of the values you passed in feedback_keys. Each value is a generated URL your client can call to submit feedback for that run.
Submit feedback with the generated URL#
When the user chooses a feedback option, POST to the corresponding URL. GET is also supported. See the LangSmith API reference for more details.
For example, if the user clicks a thumbs down button, call the user_disliked URL:
curl --request POST \
--url "https://api.smith.langchain.com/api/v1/feedback/tokens/e952734e-c0a0-417b-a04d-fc2209691ed5" \
--header "Content-Type: application/json" \
--data '{
"score": 1,
"value": 0,
"comment": "I didn't like this joke because it didn't make me laugh.",
"correction": {},
"metadata": {}
}'
```
<span class="tab-end"></span>
<span class="tab-start" data-tab-title="GET"></span>
`metadata` is not supported with `GET`.
```bash
curl --request GET \
--url "https://api.smith.langchain.com/api/v1/feedback/tokens/e952734e-c0a0-417b-a04d-fc2209691ed5?score=1&value=0&comment=I%20didn%27t%20like%20this%20joke%20because%20it%20didn%27t%20make%20me%20laugh.&correction=%7B%7D"
```
<span class="tab-end"></span>
<span class="tab-group-end"></span>
After this request succeeds, LangSmith records feedback on the trace using the key `user_disliked`.
## Optimize feedback data model
The `user_liked` and `user_disliked` keys can also be modeled under a single key such as `user_score`.
For example:
* Use `key="user_score"` with `score=1` for `user_liked`
* Use `key="user_score"` with `score=-1` for `user_disliked`
This can simplify analysis because all user preference signals are grouped under one feedback key.
The feedback data model is flexible and should be designed for your use case. For example, some applications may prefer separate boolean-style keys (`user_liked`, `user_disliked`), while others may prefer a single numeric score (`user_score`) or a richer rubric with multiple feedback keys.
## Productionize in a client UI
A productionized solution will expose the generated feedback URLs through your frontend instead of calling them manually.
Example high-level implementation:
1. Create the run from your backend or frontend.
2. Capture the `feedback` object and store the returned URLs.
3. Render feedback controls such as thumbs up/down buttons and feedback forms.
4. On feedback submission, `POST` or `GET` a feedback URL based on the user's feedback intent.
5. Optionally disable the feedback controls after submission and show confirmation to the user.
***
<span class="callout-start" data-callout-type="note"></span>
[Edit this page on GitHub](https://github.com/langchain-ai/docs/edit/main/src/langsmith/agent-server-feedback.mdx) or [file an issue](https://github.com/langchain-ai/docs/issues/new/choose).
<span class="callout-end"></span>
<span class="callout-start" data-callout-type="note"></span>
[Connect these docs](/use-these-docs) to Claude, VSCode, and more via MCP for real-time answers.
<span class="callout-end"></span>