Nox-Lumen MfgNox-Lumen Mfg

graft-comboagent

本页关注点

本页讲的是 本地宿主版 的 combo agent 客户端:装在 Cursor / Claude Code / Codex / Trae 里、通过 HTTPS 访问云端 combo agent。和它对应的云端 builtin 版 graft 请看 skills/agentic/graft;底层机制看 核心概念 · Graft

它解决什么问题

工程师每天的工作分两端:

  • 云端 combo agent:跑 ASPICE 追溯、需求审计、跨基线变更分析、新颖性检索等"重型"分析任务,并沉淀到云端 KB
  • 本地 IDE(Cursor / Claude Code / Codex / Trae):改代码、跑测试、提 PR、写文档

两端要打通的不止是"复制粘贴 session 摘要"。graft-comboagent 在一个 skill 包里把这件事抽成 三类用途

用途解决什么主要 action
A · KB 检索让本地 agent 把云端 KB 当成 RAG 数据源——不依赖云端 session 也能直接查文档 / chunklist_kbs · kb_detail · list_documents · get_doc_profile · list_chunks · search --source document
B · Session 嫁接把云端已有 session 的 digest / round / 产出物拉到本地上下文里继续工作list_sessions · get_digest · get_round · search --source round · read_file · download · list_files · search_by_artifact · grep_file
C · 任务派发把一段新指令丢回云端某个长寿命 session 异步跑(重型计算 / 工具栈不在本地 / 需要别人继续跟进)dispatch_task

A 类是纯 RAG(不开 session);B 类是只读 graft;C 类是唯一一种"写入"入口——它不能创建/删除 session 或文件,只能给 已存在 的 session 多触发一轮。

架构

Rendering diagram…
  • 服务端:api/apps/graft_app.py 暴露 user-level 端点
  • 认证:复用 web UI 的 itsdangerous 签名 access_token,登录走平台已有的 /v1/user/login
  • 客户端:4 个 Python 脚本(login / whoami / logout / call)+ 单一公钥文件
  • 写动作(如 register_artifact / copy_kb_document / save_*)在 client 与 server 双层拦截;只有 dispatch_task唯一允许 的写入路径

安装

graft-comboagent 是一个独立目录(在仓库 skills/graft-comboagent/,公开仓 Nox-Lumen-tech/combo-skills)。装到对应宿主:

宿主安装命令官方 Skills 文档
Cursorcp -r skills/graft-comboagent ~/.cursor/skills/
ln -s $(pwd)/skills/graft-comboagent ~/.cursor/skills/graft-comboagent
cursor.com/docs/skills
Claude Codecp -r skills/graft-comboagent ~/.claude/skills/code.claude.com/docs/en/skills
Traecp -r skills/graft-comboagent ~/.trae/skills/docs.trae.ai/ide/skills
Codexcp -r skills/graft-comboagent ~/.codex/skills/(随仓库内 SKILL.md 标准)

Cursor 同时也会扫描 ~/.claude/skills/~/.codex/skills/,所以软链一份在 ~/.cursor/skills/ 后,也可以在 Cursor / Claude Code / Codex 通用。

装完重启宿主让 skill 被 discovery 阶段加载(Claude Code 在已开会话内会实时检测,但新建顶层目录仍要重启)。

Python 依赖:

pip install requests pycryptodome

老环境只有 pycrypto 也能用,login.py 会自动 fallback。

首次使用:三步走

Step 1 · 登录

cd ~/.cursor/skills/graft-comboagent   # 或你装到的位置
python scripts/login.py

交互提示:

ragbase server URL [https://mfg.nox-lumen.com]:
email: me@example.com
password: ********
[OK] Logged in as me@example.com (user=ab12cd34…)

URL 默认值是 https://mfg.nox-lumen.com。如果你的私有部署在别处,直接覆盖一行就好。

发生了什么:

  1. 读 skill 包根目录下的 public.pem
  2. 用 RSA 加密 password(与 web UI 的 crypt() 完全一致)
  3. POST /v1/user/login → 拿到 signed_auth_token
  4. 写入 ~/.config/graft-comboagent/token.jsonchmod 0600

Step 2 · 验证身份

python scripts/whoami.py

输出:

email      : me@example.com
user_id    : ab12cd34ef…
server     : https://mfg.nox-lumen.com
token_path : /home/me/.config/graft-comboagent/token.json

Step 3 · 试一下三类用途

# A. KB 检索
python scripts/call.py list_kbs
python scripts/call.py search --query 冷却系统 --source document --kb-ids "ASPICE 工程库"
 
# B. Session 嫁接
python scripts/call.py list_sessions --query 冷却
python scripts/call.py get_digest --session-id "冷却系统分析"
 
# C. 任务派发
python scripts/call.py dispatch_task --session-id "冷却系统分析" \
  --prompt "对照新提交的 src/cooling/*.c 重新跑一次 ASPICE 追溯"

能力清单

所有命令通过 scripts/call.py 走,token 自动从 ~/.config/graft-comboagent/token.json 加载。

Skill 包内自带 references/action-decision-tree.md — 一个按用户意图分支的快表("我想找一篇文档" / "我想看历史 session" / "让云端帮我跑一下"),本地 LLM 在选 action 之前应当先扫这张表,避免误用。

A · KB 检索(不依赖 session 也能跑)

Action用途命令
list_kbs发现租户下可见的 KBcall.py list_kbs
kb_detail看一个 KB 的元信息(描述、文件数、向量配置)call.py kb_detail --kb-id "ASPICE 工程库"
list_documents列 KB 里的文档(支持 --query / --page-sizecall.py list_documents --kb-id "ASPICE 工程库" --query 冷却
get_doc_profile看单文档的画像(页数、解析状态、元数据)call.py get_doc_profile --doc-id <id>
list_chunks列文档的所有 chunk(跳页 / 大文档定位)call.py list_chunks --doc-id <id>
searchdocument 源=hybrid 检索(=前端"提问"按钮的能力)call.py search --query <kw> --source document --kb-ids "ASPICE 工程库"

search --source document 是 RAG 的入口;底层走平台 unified_search 的 BM25 + 向量混合检索 + rerank,跟前端 ChatBox 一致。

B · Session 嫁接(只读访问已有 session)

Action用途命令
list_sessions发现可见 session(自己的 + 团队共享)call.py list_sessions --query <kw>
get_digest看一个 session 的全貌(每轮做了什么、产出什么)call.py get_digest --session-id <x>
get_round取某轮的精确输入输出call.py get_round --session-id <x> --round-id N
searchround 源=跨 session 全文搜(--session-id "*"call.py search --query <kw> --session-id "*" --source round
search_by_artifact按产出物名找call.py search_by_artifact --query <名> --session-id <x>
grep_file文件内全文搜call.py grep_file --query <kw>
read_file服务端 markitdown 把 docx/xlsx/pdf 转 markdown 文本,节流后给 AI 阅读call.py read_file --path <p> [--center-line N --context-lines K] [--find <kw>]
download服务端 原始字节流,写本地文件(用 Office 打开 / pandas 读 xlsx)call.py download --path <p> --out ./report.docx
list_files列 session 的产出物路径call.py list_files --session-id <x>

read_file 的精读模式(避免一次拉全文)

read_file 默认会把整篇 markdown 全返。大文件(>20K tokens)建议改成精读:

# 1) 关键词定位 — 服务端先在文档里 grep <kw>,把匹配段返回
python scripts/call.py read_file --path <p> --find "DFMEA 失效模式" --max-find-matches 3
 
# 2) 行号窗口 — 已知关心 1200 行附近,取上下 50 行
python scripts/call.py read_file --path <p> --center-line 1200 --context-lines 50

C · 任务派发(唯一一种"写入")

Action用途命令
dispatch_task把新一轮 prompt 异步丢回云端 已存在 的 sessioncall.py dispatch_task --session-id NAME-OR-UUID --prompt "..."
python scripts/call.py dispatch_task \
  --session-id "ASPICE 分析" \
  --prompt "拉最新 main 上的提交,对 src/cooling 重新跑一次 SRS-to-code 追溯"

发生了什么:

  1. 服务端把这条 prompt 当成一轮新 round 入队
  2. HTTP 立刻返回(不阻塞 IDE)
  3. 云端 session 在后台异步跑
  4. 跑完后用 list_sessions / get_digest / get_round --round-id 最新 回头取结果

dispatch_task 的能力边界:只能给已存在 的 session 多触发一轮——不能新建 session、不能删 session、不能改 session 元信息。

session_id / kb_id 参数支持名称

与平台的 kb_ids / doc_ids 模式对齐——这两个参数 支持 ID,也支持人读名称,名称会自动解析为 ID:

python scripts/call.py get_digest --session-id 冷却系统分析       # 名称
python scripts/call.py get_digest --session-id 7b3c…             # ID
python scripts/call.py search --kb-ids "ASPICE 工程库,EEA 平台库"  # 多个名称逗号分隔

如果名称匹配多个,向用户确认,不要自行选一个

响应结构

所有 action 通过 scripts/call.py 走,stdout 是 JSON。统一结构:

{
  "success": true,
  "data": { /* action-specific payload */ }
}

错误时:

{
  "success": false,
  "code": "ACCESS_DENIED",   // 或 SESSION_NOT_FOUND / FILE_TOO_LARGE / ACTION_NOT_ALLOWED
  "message": "...",
  "hint": "可读建议(可选)"
}

LLM 看到 success=false 时,应当先读 code + hint,而不是直接重试同一调用。

上下文节流规则(重要)

本地 IDE 的 context 比云端紧得多。skill 自带的 SKILL.md 强约束 LLM 必须按以下顺序:

  1. session 类查询先 get_digest,获取目录型概览(5–20K tokens)
  2. 按需 drill down:digest 指明 Round N 有关键结论,才调 get_round --round-id N
  3. 大文件不全文进上下文read_file 默认调 --find / --center-line 精读;download 拿到的字节流绝不塞进 prompt
  4. KB 检索默认带 --source document:搜文档不要扫全 round(那是 B 类的事)
  5. 不做全量拖库:禁止循环 get_round 拉所有轮、循环 list_chunks 拉整个 KB、循环 download 拉所有 artifact

违反这些规则的最常见后果:本地 IDE context 在三五次调用后就崩了,AI 无法继续追问。

三个典型工作流

工作流 1(A 类)· 让本地 agent 用云端 KB 当 RAG

"我在本地写一段 EEA 控制器初始化代码,参照云端 'EEA 平台库' 里的标准实现。"

Rendering diagram…

关键节制:先用 search 定位最相关的几个 chunk,再 read_file --find 精读对应段,不要上来就把整本 KB 文档读进上下文。

工作流 2(B 类)· 嫁接已有 session

"对照云端 session 'ASPICE 分析' 的 DFMEA 结论,审查本地 src/ 下的代码,找出未覆盖的 SRS 需求。"

Rendering diagram…

工作流 3(C 类)· 让云端继续跑

"我刚改完代码 push 上去了,让云端 session 重跑一遍 ASPICE 追溯,跑完我自己回头看。"

Rendering diagram…

dispatch_task 的精髓:本地 IDE 不阻塞。重型分析丢回云端,agent 继续做手头的事,结果晚点回来取。

环境变量

变量用途默认
GRAFT_COMBOAGENT_SERVERlogin 的默认服务器 URLhttps://mfg.nox-lumen.com
GRAFT_COMBOAGENT_EMAILlogin 的默认 email
GRAFT_COMBOAGENT_TOKENtoken 文件路径~/.config/graft-comboagent/token.json
GRAFT_COMBOAGENT_DL_DIRdownload 默认落盘目录./.graft/downloads/

服务端依赖

要让本地 skill 工作,对应 ragbase 服务端必须包含这些改动:

  1. api/apps/user_app.py/v1/user/login 响应在 data 里追加 signed_auth_token(用 itsdangerous 签发)
  2. api/apps/graft_app.py 暴露:
    • POST /v1/graft/memory/unified_search — A 类(KB 检索)+ B 类(session 嫁接)所有 JSON action 入口
    • GET /v1/graft/memory/download — B 类原始字节下载
    • POST /v1/graft/dispatch — C 类任务派发

所有端点都 @login_required,权限校验完全复用现有 _verify_graft_access(同租户 + owner / 共享可见 + 写动作拦截)。

部署完成后,调用方 signed_auth_token 通过 Authorization: Bearer ... 头携带。

已知限制

  • 几乎只读:除 dispatch_task 外不能写回云端;它本身也不能新建/删除 session 或文件,只能给已有 session 触发新一轮
  • 单 profile:一次只能登录一个 ragbase server;切换需 logout.py + 重 login.py,或用 GRAFT_COMBOAGENT_TOKEN 指向不同文件
  • 不支持浏览器级 SSO:当前只支持 email + password 登录(如需 OAuth / SSO 请提需求单)
  • 单次下载 ≤ 200 MB:服务端硬上限,防止误操作拖爆带宽
  • dispatch_task 不返回最终结果:只返回入队 ack;结果用 get_digest / get_round 异步取

故障排查

症状原因处理
[FATAL] public.pem 不存在skill 目录根缺公钥文件从 ragbase conf/public.pem 复制到 skill 包根
[FATAL] 服务器没有返回 signed_auth_token服务端没部署 login 响应追加字段的改动联系管理员升级到含 graft 改动的 ragbase
[ERR] 未登录本地 token 文件不存在python scripts/login.py
HTTP 401 / 认证失效access_token 被别处 login 重置重新 python scripts/login.py
code: ACCESS_DENIED目标 session / KB 不在你可见范围确认 owner / 共享关系;换 session_id / kb_id
code: NOT_FOUNDpath 拼错或文件不存在list_files / list_documents / grep_file 确认路径
code: ACTION_NOT_ALLOWED误用了写 action(如 register_artifact / copy_kb_documentgraft 几乎只读;只有 dispatch_task 可写
code: FILE_TOO_LARGE超过 200 MB 服务端硬上限让产出物发布时做分卷或专用下载通道
dispatch_task 之后 session 没动session 已被 close/暂停get_digest 看 session 状态,状态正常再重发

与云端 builtin graft 的对照

维度云端 agentic/graft本地 graft-comboagent(本页)
谁在调combo agent 平台上的 Agent用户本地 IDE(Cursor / Claude Code / Codex / Trae)里的 AI
调用通道平台进程内 FunctionTool 直调 unified_search本地 Python 脚本 → HTTPS → ragbase 端点
认证平台 session 内置本地 ~/.config/graft-comboagent/token.json
用途范围单一:跨 session graft(B 类)三类:A KB 检索 + B session 嫁接 + C 任务派发
大文件处理Agent 上下文里直读read_file --find / --center-line 精读,或 download 落地后再 Read
写操作通过其他 builtin skill 实现几乎只读;dispatch_task 是唯一例外,且不能新建/删除 session

相关文档

On this page