独立仓接入 · 每步改什么、怎么改
下文用仓库根 <repo>/my-agent/、Python 包 my_agent 举例。步骤 4 会把 demo「回声 bot」改成「三步摘要 bot」——你可以照抄结构,只换 prompt 和业务逻辑。
先认清目录(builder 不在 nodes/)
builder.py 在 my_agent/builder.py,与 nodes/ 平级。nodes/ 里只有 run.py 等节点函数。<repo>/my-agent/
├── pyproject.toml ← 步骤 1、6
├── .env ← 步骤 3
├── tests/test_smoke.py ← 步骤 7
└── my_agent/
├── builder.py ← 步骤 4c(串图)
├── state.py ← 步骤 4b
├── core.py ← 步骤 5
├── cli.py ← 一般不改
├── server.py ← 步骤 6(pod)
├── nodes/run.py ← 步骤 4a(业务逻辑)
├── nodes/__init__.py ← 步骤 4c(多节点时)
└── prompts/__init__.py ← 步骤 4a(prompt)
起仓 + 全局改名
- 下载模板 zip,目录改名为
my-agent - 把 Python 包目录
your_agent/改名为my_agent/ - 全局替换占位符
your-agent→my-agent,your_agent→my_agent
curl -fL http://gov-agents-ui.bmaicsaws-prod.com/portal/v1/agent-template/download.zip -o /tmp/tpl.zip
unzip /tmp/tpl.zip && mv standalone-agent-template my-agent && cd my-agent
mv your_agent my_agent
grep -rl 'your[-_]agent' . | xargs sed -i '' 's/your-agent/my-agent/g; s/your_agent/my_agent/g'
git init && git add -A && git commit -m "init my-agent"
改文件:<repo>/my-agent/pyproject.toml
改完后应包含(核对 3 处):
name = "my-agent"
[project.scripts]
my-agent = "my_agent.cli:app"
[tool.setuptools.packages.find]
include = ["my_agent*"]
grep -r your_agent . 无输出 · ls my_agent/builder.py 存在配 Nexus 凭据
改文件:~/.netrc(用户主目录,不在项目里)
printf 'machine nexus.bitmartpro.com\nlogin pypi_pull\npassword 08gk5p2Q\n' >> ~/.netrc
chmod 600 ~/.netrc
uv sync 不报 401安装依赖 + LLM key + 首次跑通
改/新建:<repo>/my-agent/.env
- 在仓库根执行
uv sync - 复制
.env.example→.env - 在
.env填入ANTHROPIC_API_KEY=sk-ant-...(或用 OpenAI 则配对应 key,见 pyproject 依赖)
uv sync
cp .env.example .env
# 编辑 .env,写入 ANTHROPIC_API_KEY=...
uv run my-agent run "你好"
success=True 和一句回复(无 key 时走 echo 兜底也算过)写业务图(核心 · 4 个子步骤)
目标:把「原样回声用户输入」改成「对用户输入做三步摘要」。按顺序改下面 4 个文件。
4a · 改 prompt
<repo>/my-agent/my_agent/prompts/__init__.py
改前(模板默认):
RUN_SYSTEM = "你是一个有用的助手,简洁、准确地回答用户的问题。"
改后(你的业务 prompt):
RUN_SYSTEM = """你是发布说明助手。对用户给的内容输出三步摘要:
1. 背景(一句话)
2. 关键变更(最多 3 条 bullet)
3. 建议动作(一句话)
用中文,总字数不超过 200。"""
4b · 改 state(如需新字段)
<repo>/my-agent/my_agent/state.py
单节点 demo 可不改(继续用 input / output)。若多步节点之间要传中间结果,再加字段:
class AgentState(TypedDict, total=False):
input: str
output: str
summary: str # ← 例:scan 节点写入,run 节点读取
4c · 改节点业务逻辑
<repo>/my-agent/my_agent/nodes/run.py
改前:模板已是 LLM 调用,主要确认 import 和 prompt 引用
改后(保持结构,换 prompt + 可选解析):
from langchain_core.messages import HumanMessage, SystemMessage
from ai_trust_toolkit.llm import get_llm # 必须走 toolkit,不要直连 anthropic SDK
from ..prompts import RUN_SYSTEM
from ..state import AgentState
def run_node(state: AgentState) -> AgentState:
text = state.get("input", "")
try:
resp = get_llm("sonnet").invoke(
[SystemMessage(content=RUN_SYSTEM), HumanMessage(content=text)]
)
out = getattr(resp, "content", str(resp))
if isinstance(out, list):
out = next((b.get("text", "") for b in out if isinstance(b, dict)), str(out))
except Exception:
out = f"(echo · 未接 LLM){text}"
return {"output": out} # 写回 state · builder 里注册的节点名仍是 "run"
4d · 串图(单节点通常不用改)
<repo>/my-agent/my_agent/builder.py
仍在包根,不在 nodes/。单节点 demo 保持不动即可:
from .nodes import run_node
from .state import AgentState
def build_graph():
from langgraph.graph import END, StateGraph
g = StateGraph(AgentState)
g.add_node("run", run_node) # "run" 对应 nodes/run.py 的函数
g.set_entry_point("run")
g.add_edge("run", END)
return g.compile()
若加第二节点(例 scan → summarize):
- 新建
my_agent/nodes/scan.py,写def scan_node(state): ... - 在
my_agent/nodes/__init__.py加from .scan import scan_node - 在
builder.py里g.add_node("scan", scan_node)、改 entry 和 edge
uv run my-agent run "本次发版改了登录和支付模块" → 输出应是三步摘要格式,不是简单回声接 telemetry(Portal 看见 KPI)
<repo>/my-agent/my_agent/core.py
- 成功判定(约第 40 行):把
bool(final.get("output"))换成你的标准,例如输出非空且不含(echo - 效果指标名(约第 61 行):把
record_effect("done", 1)改成业务 key,如record_effect("summarized", 1)
# core.py · run_agent 内
success = bool(final.get("output")) and "(echo" not in str(final.get("output", ""))
# core.py · _report 内
if result.success:
record_effect("summarized", 1) # ← Portal 上显示的领域效果名
--no-telemetry 跑一次 → 几分钟后 Portal /agents/my-agent 出现 invocation + summarized 计数选入口形态(按需)
只 CLI:步骤 3 已有,不改文件。
+ Pod HTTP:
- <repo>/my-agent/pyproject.toml — dependencies 加一行:
"fastapi>=0.110", "uvicorn>=0.30", - <repo>/my-agent/my_agent/server.py — 底部启用 app:
app = _make_app() # 把原来的 app = None 改成这行 - 启动:
uv run uvicorn my_agent.server:app --port 8080 - 调用:
curl -X POST http://127.0.0.1:8080/agents/my-agent/run -H 'Content-Type: application/json' -d '{"input":"测试"}'
+ MCP:需另建 my-agent-mcp 包,参考平台 apps/bmc-agent-mcp(本教程不展开)。
补测试
<repo>/my-agent/tests/test_smoke.py
模板已有 2 条冒烟。可加一条断言输出格式:
def test_output_has_summary_structure():
out = build_graph().invoke({"input": "发版说明:修复了 A 模块"})
text = out.get("output", "")
assert text
# 有 LLM 时可断言包含序号;无 key echo 时跳过严格断言
if "(echo" not in text:
assert "1." in text or "背景" in text
uv run --extra test pytest -v # 必须 --extra test
安全自检 · 上线
步骤 8:若 agent 用服务凭据调 GitLab/工单/DB → 填 Day 05 安全 7 问(改方案文档,无固定代码文件)。本机 CLI + 用户自己的 key 通常可跳过正式评审。
步骤 9:在 <repo>/my-agent/ 根目录:
uv build
uv publish --publish-url http://nexus.bitmartpro.com/repository/bm-pypi/ \
--username '<NEXUS_USER>' --password '<NEXUS_TOKEN>' dist/*
队友安装:pipx install --index-url http://nexus.bitmartpro.com/repository/local-pipy/simple/ my-agent
Monorepo 路径 → 同样业务改法,但 server 用 build_v1_router、另改 platform 注册文件 → Day 03 实操