CopilotKit 集成指南:Langroid 下 Agent 配置对象(tone / expertise / responseLength)的前端到后端全链路
【免费下载链接】CopilotKitThe Frontend Stack for Agents & Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit
导读
本指南面向在 CopilotKit 与 Langroid 集成场景中需要“让用户配置 Agent 语气、专业度、回答长度”的开发者。它以showcase/integrations/langroid示例仓库中的 agent-config 演示为核心,完整讲解从 React 前端配置卡片、AG-UI 协议转发、Next.js 路由重打包,到 Langroid Python 后端动态拼接系统提示词的端到端实现与验证方案。读完本文,你将掌握:如何通过CopilotKit properties或useAgentContext将前端状态注入 Agent 运行时,如何在 AG-UIforwardedProps中安全传递结构化配置,以及如何编写对应的 Playwright 端到端测试来固化这一行为。
背景:CopilotKit 与 Langroid 集成中的“配置对象”需求
在 CopilotKit 的生态中,前端组件(React、Angular 等)负责渲染对话与生成式 UI,而真正的 Agent 逻辑运行在服务端。CopilotKit 通过 AG-UI 协议(@ag-ui/client)将前端消息、工具调用与状态转发给后端运行时。Langroid 是 CopilotKit 官方示例中支持的服务端 Agent 框架之一,其完整示例位于 showcase/integrations/langroid。
所谓“Agent 配置对象(Agent Config Object)”,指的是:前端通过 UI 控件(下拉框等)选择一组用于控制 Agent 输出风格的属性,并随每次对话运行请求一并发送到后端,后端据此在本次运行时调整系统提示词,从而改变回复的语气、深度与长度。在 agent-config 演示中,这一组属性是三个键:tone(语气)、expertise(专业程度)、responseLength(回答长度)。
该演示的 QA 验证文档位于 showcase/integrations/langroid/qa/agent-config.md,对应的前端源码位于 showcase/integrations/langroid/src/app/demos/agent-config/,后端适配逻辑位于 showcase/integrations/langroid/src/agents/。以下内容将围绕“QA 文档的测试步骤 + 源码实现细节”展开,帮助你既会测、又懂原理。
前置条件
在复现本演示与执行验证之前,需要满足:
- Demo 已部署且可访问:
/demos/agent-config页面能够正常打开。 - Agent 后端可达:
/api/copilotkit-agent-config路由已就绪(这是本演示专用的 CopilotRuntime 路由)。 - Langroid Agent 服务正在运行:可通过
/api/health探活确认。
在上述条件满足后,你就可以按照下面的测试步骤逐项验证配置对象的全链路行为。
测试步骤一:配置 UI 是否正常渲染
首先验证前端配置卡片本身。打开/demos/agent-config页面,确认:
data-testid="agent-config-card"的元素可见;- Tone / Expertise / Response length三个下拉选择器均已渲染。
源码印证:配置卡片的实现
配置卡片由 config-card.tsx 实现,其根节点正是data-testid="agent-config-card",三个下拉框分别带有data-testid="agent-config-tone-select"、data-testid="agent-config-expertise-select"、data-testid="agent-config-length-select"。三个下拉框的可选项并非硬编码在 JSX 里,而是从 config-types.ts 中的常量导入:
TONE_OPTIONS:professional、casual、enthusiastic;EXPERTISE_OPTIONS:beginner、intermediate、expert;RESPONSE_LENGTH_OPTIONS:concise、detailed。
AgentConfig类型与默认值也定义在此处,默认配置为{ tone: "professional", expertise: "intermediate", responseLength: "concise" }。
对应地,Playwright 端到端测试 tests/e2e/agent-config.spec.ts 的第一个用例正是断言这些默认值:三个下拉框初始值分别为professional、intermediate、concise,且页面包含输入消息的占位符。
测试步骤二:前端属性确实到达 Agent(行为验证)
这是整个配置对象机制的核心验证,QA 文档给出了三个行为断言:
- 将Tone改为
enthusiastic,发送 “Hello”,应产生回复,且语气应明显更热情/温暖。 - 将Expertise改为
expert、Response length改为detailed,发送 “Explain how LLM tool calling works”——回复应自由使用领域术语,且为多句而非 1~2 句。 - 将Response length改为
concise、Expertise改为beginner,发送相同问题——回复应控制在 1~2 句、避免行话,并在首次出现技术术语时给出定义。
前端状态如何流入运行时
页面根组件 page.tsx 使用useAgentConfig()Hook 持有tone / expertise / responseLength三份状态,并将其分别传给配置卡片与聊天布局 demo-layout.tsx(后者挂载CopilotChat)。状态本身的增删改逻辑在 use-agent-config.ts 中,提供setTone / setExpertise / setResponseLength / reset四个更新入口。
配置状态真正“进入”Agent 运行时有两个通道:
- 通道一(v2 推荐):
useAgentContext。config-context-relay.tsx 位于<CopilotKit>Provider 内部,通过useAgentContext({ description, value })将当前AgentConfig发布到 Agent 运行时上下文。文件注释明确指出:这是 v2 版本 “frontend → agent runtime context” 的标准写法(对应 LangGraph 0.6+ 对context的引入),Python 侧中间件会在每轮对话前把该上下文条目注入模型提示词。 - 通道二(v1 风格):
CopilotKit properties。<CopilotKit properties={...}>依然可用,但它经由forwardedProps转发,不会落入 LangGraph 的RunnableConfig(在@ag-ui/langgraph0.0.31 中)。因此本演示的路线优先使用useAgentContext。
后端如何把属性翻译成行为
Langroid Python 后端在 agui_adapter.py 的 run 处理器中调用extract_agent_config_properties(run_input.forwarded_props)提取属性,再调用 agent.py 中的build_agent_config_system_prompt(...)生成动态系统提示词。属性到提示词的映射关系(_TONE_DIRECTIVES/_EXPERTISE_DIRECTIVES/_LENGTH_DIRECTIVES)如下:
| 属性 | 可选值 | 注入的系统提示词指令(摘要) |
|---|---|---|
tone | professional/casual/enthusiastic | 分别对应“专业、沉稳”“随意、口语化”“热情、温暖、振奋” |
expertise | beginner/intermediate/expert | 分别对应“分步讲解、避免行话、首现术语即定义”“可用常见术语但不跳过非显然概念”“自由使用领域术语、跳过铺垫” |
responseLength | concise/detailed | 分别对应“1~2 句简短回答”“多句或短段落、给出可行动的上下文” |
build_agent_config_system_prompt的行为是:把命中的指令以User-selected style:为标题拼接到SYSTEM_PROMPT之后;对未知值(包括None)静默跳过,因此即使只传了一部分属性,也能生成可用的提示词,不会因前端异常而让整轮对话 500。后端对三个属性的取值集合做了frozenset白名单校验(_AGENT_CONFIG_TONES等),核心意图是“宁可提示词不被引导,也不要在前端 bug 时让 Agent 报错”。
关键设计点:这种引导只作用于当前运行(this run only)。QA 文档与源码注释都强调,配置对象影响的是本次运行的系统提示词拼接,不会污染其他 demo 或后续对话——其他 demo 的
forwarded_props为空或缺少这些键时,extract_agent_config_properties返回None,后端行为完全不变。
测试步骤三:网络层深挖——请求体的重打包形态
这一节是可选但更深入的验证,用于确认“配置对象”在 AG-UI 协议层的实际传输形态。
操作步骤
- 打开浏览器 DevTools 的 Network 面板;
- 发送一条消息,观察发往
/api/copilotkit-agent-config的 POST 请求; - 在请求体中确认
forwardedProps.config.configurable.properties包含tone、expertise、responseLength以及所选值; - 反面断言:
forwardedProps.tone、forwardedProps.expertise、forwardedProps.responseLength这些扁平键不应存在——路由负责把它们重打包到config.configurable.properties之下。
为什么必须重打包:路由源码解析
专用运行时路由 src/app/api/copilotkit-agent-config/route.ts 的注释揭示了完整的来龙去脉:
- 前端 Provider 的
properties以扁平键形式出现在 AG-UI 的forwardedProps顶层(例如forwardedProps.tone); - LangGraph 上游示例(showcase/integrations/langgraph-python/src/app/api/copilotkit-agent-config/route.ts,被注释视为 canonical 实现)的 Python 图从
RunnableConfig.configurable.properties读取这些值,因此 TS 适配层需要把扁平键重打包到forwardedProps.config.configurable.properties; - Langroid 后端虽然没有 LangGraph 的
RunnableConfig,但刻意复刻同一载荷形态,目的是:(1) 让所有 showcase 的前端契约保持一致;(2) 让 Langroid Python 后端从唯一确定位置(run_input.forwarded_props.config.configurable.properties)读取——顶层扁平键未来可能与其他 AG-UI 新增的forwardedProps字段冲突。
实现层面,路由定义了一个RESERVED_FORWARDED_PROPS_KEYS集合(含config、command、streamMode、threadMetadata、checkpointId、interruptBefore、metadata等约 18 个 AG-UI / LangGraph 流载荷保留键)。repackForwardedPropsIntoConfigurable遍历forwardedProps顶层键:命中保留键的进structural(保持原位),其余视为用户前端状态进userProps,最后把userProps合并进forwardedProps.config.configurable.properties。若userProps为空则原样返回输入,避免空跑。
这个重打包动作被封装在一个HttpAgent子类AgentConfigHttpAgent中,只覆盖requestInit方法——这是 AG-UI 客户端序列化请求体的唯一位置(body: JSON.stringify(input)),因此“一次请求只重打包一次”,不需要任何中间件管道。该子类被同时注册为agent-config-demo与default两个 agent 名,因此即使内部组件以无参useAgent()默认调用,也会落到这个 agent 上。
为什么是“扁平键不能出现”:Playwright 测试的约束
agent-config.spec.ts 的 “properties object propagates to runtime requests” 用例通过page.route拦截发往/api/copilotkit-agent-config的 POST,断言请求体包含enthusiastic、expert、detailed。最后一个用例 “changing config between sends produces distinct request payloads” 更进一步:先以默认配置发送 “First”,再改为casual+detailed发送 “Second”,断言切换前的请求体包含professional/concise、切换后的请求体包含casual/detailed,证明每次运行都会携带当时的配置快照。
预期结果与验收标准
综合以上三步,agent-config 演示的完整验收标准是:
- 行为可感知:切换不同的配置值,Assistant 的“声音”(语气)、解释深度与回复长度都会肉眼可见地变化;
- 协议形态正确:
/api/copilotkit-agent-config请求体呈现重打包后的形态——扁平 Provider 键全部落在forwardedProps.config.configurable.properties下; - 作用域隔离:Langroid 后端通过 AG-UI
forwarded_props收到属性后,仅对本次运行在系统提示词中追加风格指令,其他 demo 不受影响。
从验证到原理:三层链路总结
可以把整套机制压缩为一条三层链路,便于在排查问题时快速定位:
| 层 | 组件 | 职责 | 关键证据位置 |
|---|---|---|---|
| 前端 | useAgentConfig+ConfigContextRelay+ConfigCard | 持有配置状态、渲染控件、把状态发布进 Agent 运行时上下文 | use-agent-config.ts、config-context-relay.tsx、config-card.tsx |
| 路由层 | AgentConfigHttpAgent+repackForwardedPropsIntoConfigurable | 把扁平forwardedProps键重打包为config.configurable.properties | route.ts |
| 后端 | extract_agent_config_properties+build_agent_config_system_prompt | 从forwarded_props提取属性并动态拼接系统提示词(白名单校验、未知值静默跳过) | agent.py、agui_adapter.py |
排查建议:如果前端切换配置后 Agent 行为没有变化,按“三层链路”逐段检查——① DevTools 中请求体是否包含正确配置键;② 请求体的键是否位于config.configurable.properties而非顶层;③ Langroid 后端日志中系统提示词是否被User-selected style段追加。每一步都能在对应的源码与测试文件中找到可复现的验证点。
【免费下载链接】CopilotKitThe Frontend Stack for Agents & Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考