Files
group_fqcd_jr/docs/14-Agent组员统一接入说明书.md
T
lzf_0626 36c7a9d8d2 文档:审查报告入库 + 全量校对补注
## 新入库(`docs/演示用/`)

- `代码库全面审查报告-2026-09-14.md`
- `代码修改方案-2026-09-14.md`
- `记忆系统排查报告-2026-09-14.md`
- `记忆系统修复文档-2026-09-14.md`
- `文档一致性审计报告-2026-09-14.md`
- `多Worker接入方案-2026-09-14.md`

## 全量校对(32 个既有文档 + `AGENTS.md`)

跨 39 个文件、**1125 insertions / 148 deletions**。

⚠️ **这批改动同样不是本次会话写的**。我抽样核对过性质:是**实质内容补充**而不是
格式/换行转换。例如 `docs/44-演示流程.md` 新增两条"2026-09-14 补注":

- `启动金融Agent平台.bat` 只在**桌面**上,仓库里只有 `启动平台.bat` 这一份
  (两份由同一个 `tools/make_launcher_bat.py` 产出,改完 `start.ps1` 重跑它一起更新);
- `advisor_t`(9020) 与 `offsite_t`(9006) **不在 `tools/seed_test_rbac.py` 的演示用户里**
  (那里只有 `cust_t`/`risk_t`/`admin_t`/`review_t` 四个),由 `grant_*.py` 系列创建,
  **重跑种子不会重建它们** —— 换机器时这两个账号登录失败,要先查 `sys_user` 有没有这两行,
  而不是查密码。

这两条都是对的地方,与我这一路踩到的现象一致(我确实用到了 `advisor_t`/`offsite_t`)。

**我没有逐字审阅全部 39 个文件**,只抽样确认了改动性质与规模。若其中有需要复核的段落,
请指明文件,我逐处核对。
2026-09-14 20:36:00 +08:00

14 KiB
Raw Blame History

Agent 组员统一接入说明书

版本:v1.0
适用对象:客服、投顾、风控及其他业务 Agent 开发人员
阅读要求:组员开发 Agent 前必须完整阅读本文。

本文是业务组员接入底座的统一入口,整合了底座启动、Agent 注册、公共执行链、模型、意图、工具、 适当性、基金行情和提交验收要求。接口字段以《05-接口文档.md》为准,数据库以《00-新数据库基线设计.md》 和《02-数据库建表设计.md》为准。

1. 你负责什么,底座负责什么

业务 Agent 属于 MVC+S 架构的 Service 层。组员只负责业务意图、业务编排和业务输出,不负责重建公共底座。

组员负责:

  • AgentDefinition;
  • 继承 BaseAgent 的业务类;
  • handle() 内的业务判断和编排;
  • 业务只读工具声明及测试;
  • 注册表登记;
  • 业务边界和权限测试。

底座负责:

  • JWT、RBAC、入口和客户范围校验;
  • 配置快照和记忆召回;
  • 意图分类和低置信处理;
  • 模型路由、密钥引用和 fallback;
  • 工具权限、超时、审计和来源引用;
  • 适当性校验;
  • 合规审查、敏感信息脱敏;
  • 运行持久化、Outbox、SSE 和恢复。

业务范围只包括场内基金模拟交易。场外运营必须独立建表、独立接口,不得写入场内交易表。

2. 接入前提

项目使用项目自带虚拟环境(Python 3.13,实测 3.13.5):

.\.venv\Scripts\python.exe -m pip install -r requirements.txt

复制配置模板并填写本机环境:

Copy-Item .env.example .env

启动 HTTP 服务和 Worker:

.\.venv\Scripts\python.exe -m uvicorn app.main:app --host 127.0.0.1 --port 8099
.\.venv\Scripts\python.exe -m app.worker

数据库迁移只能通过 Alembic:

.\.venv\Scripts\python.exe -m alembic upgrade head
.\.venv\Scripts\python.exe tools\audit_schema.py

.env、JWT 私钥、模型 API Key 不得提交到 Git。

3. 定义 Agent

agent_type 必须使用小写蛇形命名,例如 customer_service、advisor、risk。 supported_intents 列出该 Agent 支持的全部意图;配置中心不能扩大代码中声明的工具上限。

from app.core.contracts import AgentDefinition, AgentRequest, CoreResult, RequestContext
from app.service.agent.base import BaseAgent


class AdvisorAgent(BaseAgent):
    definition = AgentDefinition(
        agent_type="advisor",
        version="1.0.0",
        allowed_roles=("customer", "advisor", "operator", "admin"),
        allowed_portals=("api",),
        allowed_tools=("query_fund_quote",),
        supported_intents=("fund_quote", "general"),
    )

    async def handle(self, request: AgentRequest, context: RequestContext) -> CoreResult:
        return CoreResult(text="业务处理结果")

业务类只实现 handle()。不要覆盖 execute()、鉴权、配置、记忆、意图分类、模型、工具或合规方法。

4. 注册 Agent

在 app/service/agent/bootstrap.py 的统一注册入口登记:

factory.register(
    AdvisorAgent.definition,
    lambda _context: AdvisorAgent(AdvisorAgent.definition),
)

HTTP 服务和 Worker 使用同一个工厂,不能各自维护注册表。构造器必须返回 BaseAgent,且实例的 AgentDefinition 必须与注册定义完全一致。

注册完成后必须通过:

python -m pytest tests/contract/test_agent_factory_contract.py -q -p no:cacheprovider

未注册的 Agent 类型会返回 404 AGENT_TYPE_NOT_FOUND。

5. 公共执行顺序

每次运行固定经过:

输入校验
→ JWT/RBAC/入口/客户范围校验
→ 读取发布配置
→ 召回授权记忆
→ 自动意图分类
→ 执行 handle()
→ 模型、工具和适当性治理
→ 引用、禁止表达和敏感信息审查
→ complete_run 同事务持久化、审计和 Outbox
→ 查询/SSE 返回结果

组员只能读取 self.config、self.memories、request 和服务端生成的 context。客户身份以 context 为准,不信任客户端自行传入的身份字段。

6. 意图分类

组员不需要创建 IntentClassifier、调用 ModelRouterService 或传 endpoints。底座会在 handle() 前从当前激活的模型端点自动分类,并把结果写入 CoreResult.intent。

模型输出必须是严格 JSON:

{"intent":"fund_quote","confidence":0.92}

底座会校验:

  • 意图必须属于 supported_intents;
  • confidence 必须在 0 到 1;
  • 低于配置阈值时 needs_clarification=true;
  • 非法 JSON、未声明意图和空输入失败关闭。

低置信结果不能当作确定意图继续执行高风险业务。

7. 模型调用

模型链路固定为:

ConfigRelease → ModelRouterService → ModelGateway → 主端点/受控 fallback

业务 Agent 只能调用底座注入的方法:

result = await self.generate_with_model(endpoints, prompt)

禁止:

  • 导入 httpx 或供应商 SDK;
  • 自己读取模型密钥;
  • 自己选择未批准端点;
  • 把模型原始异常返回给用户。

模型密钥只能使用 secret_ref,不能写入代码、数据库明文、日志或接口响应。

8. 公共工具调用

工具必须通过工厂注入的 ToolExecutor 调用:

value = await self.call_tool(
    "工具名",
    {"参数": "值"},
    intent="当前意图",
    context=context,
)

每个工具必须声明 Pydantic 输入模型、权限码、允许角色、只读属性和超时。底座统一执行参数校验、 意图白名单、角色权限、超时、脱敏摘要、审计和来源引用。

底座已注册的公共只读工具(app/service/agent/bootstrap.py 的 ToolRegistry,实际注册段落在 L248-388; 原写"约 L155-192"是早期快照,行号已漂移):

工具名 必需权限 允许角色 超时 越权与失败行为
check_suitability suitability:read customer、advisor、operator、admin 默认 C1-C5/R1-R5 匹配;测评过期/缺失一律拒绝(失败关闭);通过和拒绝都写 interaction_audit
query_fund_quote fund:quote:read customer、advisor、operator、risk_operator、admin 15s 只读行情,不得改写为成交、委托或持仓语义。15s 的来历:EastmoneyAdapterFactory 单代码最坏预算 4.0s+0.2s+4.0s=8.2s,15s≈8.2×1.8;原值 5s 会先撞工具超时
search_knowledge knowledge:reference:read customer、advisor、operator、admin 10s 这是知识检索的正式名。集合名由服务端按意图映射,调用方不得指定;维度不符失败关闭
query_knowledge knowledge:query visitor、customer 10s ⚠️ 是 search_knowledge 的别名(同一 handler,见下方说明),不是另一个工具
query_customer_profile memory:read:self(读他人需 memory:read:customer) customer、advisor、operator、risk_operator、admin 默认 越范围按"不存在"处理且不泄露存在性;无当前画像抛错而不返回空画像

⚠️ search_knowledge 与 query_knowledge 的主次关系(原文档写反了): bootstrap.py:309-319 注册的是 search_knowledge(权限 knowledge:reference:read, 角色含 advisor/operator/admin,不含 visitor);bootstrap.py:321-328 的 query_knowledge 是别名,同一 handler(knowledge_search_tool), 仅为兼容一期发布配置与旧客户端保留,权限 knowledge:query、角色只有 visitor/customer。

两者都要发布(见 AGENTS.md):知识类意图若只发 search_knowledge, 访客令牌只有 knowledge:query,一问即失败;只发 query_knowledge, 登录客户与投顾那侧又缺权限。原文档把 query_knowledge 当主名、并把它的角色集写成 "customer、operator、advisor、risk_operator、admin",两处均与代码不符。

工具白名单是两段式:代码里的 AgentDefinition.allowed_tools 是上限,实际可用范围还要与 当前 active 的 config_release 中 namespace=agent_tools、config_key=<agent_type>:<intent> 发布的工具白名单取交集;缺发布配置时交集为空、工具失败关闭。公共工具的接口面登记口径 见《05-接口文档.md》§8.4。

其余工具按业务线各自注册(不在公共只读工具之列,权限码也不同):

业务线 工具 权限码
风控 search_risk_alerts、get_risk_overview、get_alert_evidence risk:alert:read
投顾 query_investment_goal、analyze_portfolio、generate_asset_allocation、recommend_products、compare_products 各自的 investment-goal:* / portfolio-analysis:* / asset-allocation:* / product-recommendation:* / product-comparison:*
NL2SQL query_financial_data financial:nl2sql:read
探针 PROBE_ALT_TOOL probe:read

9. 基金行情工具

底座已提供 query_fund_quote 公共只读工具(全部公共工具的清单见 §8;本节只展开行情工具):

工具名:query_fund_quote
权限码:fund:quote:read
允许角色:customer、advisor、operator、risk_operator、admin

9.1 代码和配置声明

在 AgentDefinition 中声明:

allowed_tools=("query_fund_quote",)
supported_intents=("fund_quote", "general")

在已发布配置中声明:

namespace: agent_tools
config_key: <agent_type>:fund_quote
value_json: {"allowed_tools": ["query_fund_quote"]}

9.2 调用方式

quote = await self.call_tool(
    "query_fund_quote",
    {"fund_codes": ["159511"], "limit": 20},
    intent="fund_quote",
    context=context,
)

返回结果重点关注:

  • quote_source:eastmoney、cache 或 degraded;
  • is_intraday:是否盘中行情;
  • degraded:是否降级;
  • nav_date:净值对应日期。

降级行情只能用于说明和分析,不能表述为成交、委托、持仓或实时保证。

禁止直接导入 hq.py、调用东方财富 URL、使用 httpx 或自行读取行情缓存。

10. 适当性校验

投顾相关流程必须调用公共 SuitabilityService 或 check_suitability 工具,不得复制 C1-C5/R1-R5 规则。客户风险等级低于产品风险等级、测评过期时必须拒绝;专业投资者也不能绕过审计。

通过和拒绝决定都会写入 interaction_audit,服务只读,不修改交易、产品或客户风险资料。

11. 记忆、关系和转人工

  • 记忆提取由 complete_run() 在同一事务写入 Outbox,组员不直接调用提取服务;
  • 记忆只能读取当前客户授权范围;
  • Neo4j 查询必须经过 RelationshipService 和关系白名单;
  • Agent 只能提出转人工请求,不能分配、接单、解决或关闭工单;
  • 不能伪造 SourceReference,只能引用本次授权召回或工具真实返回的数据。

12. 禁止事项

  • 禁止绕过 AgentFactory、BaseAgent、统一鉴权、记忆、模型、工具、合规、审计和事件流程;
  • 禁止直接创建 SQLAlchemy Session、访问 MySQL、Redis、Milvus 或 Neo4j Driver;
  • 禁止代客下单、确认成交、修改持仓、审核方案、处置或关闭风险预警;
  • 禁止把场外运营数据写入场内交易表;
  • 禁止重命名、删除或修改已有数据库表和字段;数据库需求只能新增表或字段并先对照基线。

13. 提交前测试

业务 Agent 至少覆盖:

  • 正常意图、低置信意图和模型格式错误;
  • 未授权角色、入口、权限和客户范围;
  • 工具白名单、参数错误、超时和失败关闭;
  • 适当性通过、风险不匹配和测评过期;
  • 行情正常、缓存、降级和非交易时段;
  • 禁止表达、敏感信息脱敏、来源引用和最终持久化。

统一验收命令:

python -m pytest -q -p no:cacheprovider
python -m ruff check app tests tools alembic
python -m mypy app
python tools/check_authoritative_docs.py
python tools/audit_schema.py

14. 当前状态

app/service/agent/bootstrap.py 的 register_business_agents()(实际 L407-447,原写"约 L218-225"已漂移) 已注册 7 个业务 Agent(原文档写"两个",已过期):

# Agent 类 agent_type 说明
1 FundQueryDemoAgent fund_query_demo 示例 Agent,fund_quote 意图 + query_fund_quote 工具
2 CustomerServiceAgent customer_service 客服 Agent,五类意图(faq/product_inquiry/policy_explain/chitchat/transfer_human)。⚠️ 现用 search_knowledge(原写"使用 query_knowledge"是旧口径;query_knowledge 只留给访客令牌)
3 RiskAgent risk 风控,4 意图(risk_overview/risk_search/risk_evidence/general)+ 3 工具
4 OffsiteFundAgent offsite_fund 场外基金运营
5 PromotionMaterialAgent promotion_material 推广材料
6 PlatformProbeAgent platform_probe 平台探针(联调自检用)
7 AdvisorAgent advisor 投顾:6 意图 + 6 工具(含 NL2SQL)

上表公共只读工具均已注册并可供业务 Agent 使用,但业务 Agent 必须完成自己的代码声明、 意图白名单配置和注册后才能调用。新增的业务 Agent 若未注册,提交其 agent_type 会返回 404 AGENT_TYPE_NOT_FOUND。

注册顺序不是任意的:bootstrap.py 中注册次序为演示 Agent → 客服 → 风控 → 场外 → 推广 → 探针 → 投顾。新增 Agent 请追加在末尾,不要在中间插入,以免 diff 冲突。

推荐阅读顺序:本文 → 《05-接口文档.md》→ 对应业务域流程文档。本文不替代接口文档和数据库基线。