这不是一个“把 Kimi API 包一层页面”的普通 demo。
它记录的是一次从虚拟机环境、openYuanrong 集群、函数注册、Agent Session,到 Kimi 接入端到端跑通的完整实操。

一、用户场景:Agent 执行到一半,要停下来等人

先把要解决的问题说清楚。

很多 AI Agent 教程里,前端一个聊天框,后端调一次大模型,返回一段文本——页面能动,但严格说那只是“模型 API 调用器”,不是 Agent 工程化。

真实业务里的 Agent,往往长这样:

  • 一个文章策划 Agent:先问用户“想写什么选题、给谁看、强调什么”,停下来等用户填;用户填完,生成大纲;再停下来等用户确认;确认后才生成正文草稿。
  • 一个报销审批 Agent:跑到一半发现缺发票,挂起等用户补传,补完接着往下走。
  • 一个客服工单 Agent:需要用户二次确认订单信息后才执行退款。

这些场景共同的难点不是“模型能不能生成”,而是:

Agent 执行到一半需要停下来等用户补充信息,等信息回来后,还要沿着原来的上下文继续往下执行。

用传统 Web 服务当然能做,但你得自己补一整套状态系统:Redis 存中间状态、数据库存会话、消息队列做回调,再自己处理并发和超时。写到最后会发现,模型调用反而是最简单的部分,跨请求的状态编排才是真正的工程量

这次 demo 用最克制的方式验证一件事:

openYuanrong 能不能作为 Agent Runtime,让一个函数在执行过程中真正“等待 → 被唤醒 → 基于同一个 SessionID 继续”,把状态编排这件事接管掉。

不做 RAG、不做复杂工具链、不堆智能体框架——先把这条最关键的链路跑通,其余都是自然扩展。

二、demo 目标与整体链路

最终跑通的是上面说的“文章策划 Agent”,完整链路:

  1. 用户启动 Agent。
  2. openYuanrong 函数进入 wait_for_notify(),等待用户补充文章方向。
  3. 用户提交选题信息,另一个带同一 SessionID 的请求通过 notify(payload) 唤醒等待中的执行流程。
  4. Agent 调用 Kimi API 生成文章大纲。
  5. Agent 再次进入 wait_for_notify(),等待用户确认大纲。
  6. 用户确认后,再次 notify({"confirm": true})
  7. Agent 继续调用 Kimi API 生成文章草稿。
  8. 原始 start 请求返回最终结果。

这条链路里职责划得很清楚:

Kimi:        负责生成大纲和文章草稿(纯推理生成)。
openYuanrong: 负责函数部署、调用、Session 加载、等待、唤醒、
              会话亲和、会话历史和状态恢复。

换句话说,本文的核心不是“怎么调 Kimi”,而是“怎么把一个需要多轮等待的 Agent 跑在 openYuanrong 上”。下面所有截图都来自这次实际运行环境。

三、运行环境

在 Mac 主机上用 Multipass 新建了一个 Ubuntu 虚拟机,openYuanrong 集群跑在 VM 里。
在这里插入图片描述

关键环境:

Host: macOS
VM:   Ubuntu 24.04.4 LTS(yuanrong-agent-demo, 192.168.2.6, 4C/8G/40G)
Python: 3.11 virtualenv
openYuanrong: 已安装

本机项目目录 ~/openYuanrong/agent-demo,同步到 VM 后位于 /home/ubuntu/openYuanrong-agent-demo/agent-demo

四、启动 openYuanrong 集群并确认健康

VM 里启动 openYuanrong:

cd ~/openYuanrong-agent-demo
source .venv/bin/activate

yr start --master \
  -s 'mode.master.frontend=true' \
  -s 'mode.master.function_scheduler=true' \
  -s 'mode.master.meta_service=true'

这个 demo 至少需要 frontend(接收调用)、meta_service(函数元数据)、function_scheduler(调度)、function_agent(执行)、function_proxy(通信)、etcd(元数据存储)、ds_master / ds_worker(DataSystem)这些组件。

写业务代码前,先确认 openYuanrong 本身是健康的:

multipass exec yuanrong-agent-demo -- bash -lc '
source ~/openYuanrong-agent-demo/.venv/bin/activate
yr health
'

在这里插入图片描述

这是第一个关键证据:这个 demo 跑在一个真实运行的 openYuanrong 集群上,而不是普通本地 Python 服务。

五、项目结构

agent-demo/
  functions/
    agent_demo.py     # openYuanrong Agent Session 状态机(核心)
    llm_client.py     # Kimi API 客户端(核心)
    hello_demo.py
  register/
    agent.json        # 函数注册配置
    hello.json
  scripts/
    register_agent.sh
    run_agent_session.sh
    start_web.sh
  web/                # 可视化控制台(仅展示层)
    server.py
    static/
  README.md

真正的 Agent 逻辑都在 openYuanrong 函数里,Web 页面只是为了让 demo 有一个可视化控制台。

六、注册函数并开启 Agent Session

注册配置 register/agent.json

{
  "name": "0@agentdemo@kimi-agent",
  "runtime": "python3.11",
  "handler": "agent_demo.handler",
  "kind": "faas",
  "cpu": 1000,
  "memory": 1024,
  "timeout": 600,
  "concurrentNum": "10",
  "enableAgentSession": true,
  "environment": {
    "LLM_PROVIDER": "kimi",
    "LLM_BASE_URL": "https://api.moonshot.cn/v1",
    "LLM_MODEL": "kimi-k2.6"
  },
  "storageType": "local",
  "codePath": "/home/ubuntu/openYuanrong-agent-demo/agent-demo/functions"
}

注册前先在 VM 里把关键字段打出来,确认函数名、运行时、handler、Agent Session 开关和 Kimi 配置都在:

在这里插入图片描述

注册脚本做的事:从 register/agent.json 读配置 → 把 Kimi API Key 通过环境变量注入函数环境(不写进源码)→ 调用 meta_service 注册或更新函数 → 把响应里的敏感字段脱敏为 *** → 保存函数 URN。

cd ~/openYuanrong-agent-demo/agent-demo
MOONSHOT_API_KEY="你的 Kimi API Key" bash scripts/register_agent.sh

注册走的是 openYuanrong REST API(函数已存在则走 PUT 更新):

POST http://192.168.2.6:31182/serverless/v1/functions

在这里插入图片描述

最重要的是这个 URN:

sn:cn:yrk:default:function:0@agentdemo@kimi-agent:latest

后续所有调用都不是直接执行 Python 文件,而是请求 /serverless/v1/functions/{URN}/invocations——这是“请求进了 openYuanrong”的第二个证据。

七、确认 Agent Session 真的生效

注册成功还不够,普通函数也能注册成功。我们要证明它真的启用了 Agent Session,所以进一步查 etcd 里的函数元数据:

multipass exec yuanrong-agent-demo -- bash -lc '
ETCDCTL_API=3 ~/openYuanrong-agent-demo/.venv/lib/python3.11/site-packages/yr/third_party/etcd/etcdctl \
--endpoints=http://192.168.2.6:32379 \
get /sn/functions/business/yrk/tenant/default/function/0@agentdemo@kimi-agent/version/latest -w json \
| jq -r .kvs[0].value | base64 -d \
| jq "{handler: .funcMetaData.handler, enableAgentSession: .extendedMetaData.enableAgentSession, code_path: .codeMetaData.code_path}"
'

在这里插入图片描述

最关键的一行:

"enableAgentSession": true

这证明这个函数不是普通 FaaS 函数,而是启用了 openYuanrong 的 AI Agent Session 能力。

八、Agent 函数:等待 → 唤醒 → 继续

核心入口在 functions/agent_demo.py
在这里插入图片描述

函数一进来,先从 openYuanrong context 里拿 session:

session_id = context.get_session_id()
session = context.get_session_service().load_session(session_id)

如果调用请求没有携带可被 openYuanrong 识别的 SessionID,就拿不到可用 session。本文 REST 调用里,SessionID 放在 X-Instance-Session Header 中:

if session is None:
    return {
        "status": "missing_session",
        "message": "请在调用 Header 中传入 X-Instance-Session。",
        "session_id": session_id,
    }

当请求是 notify 时,函数不进入主流程,只向当前 Session 发通知。会话绑定有效时,这个请求会因为会话亲和落到同一实例,唤醒之前挂起的执行线程:

if action == "notify":
    payload = event.get("payload") or {}
    session.notify(payload)
    return {"status": "notified", "session_id": session_id, "payload": payload}

主流程第一步:记录状态,然后等待用户补充信息:

_record(session, "collect_info",
        message="请提交文章目标读者、风格、痛点和你想强调的 demo 方向。")

user_info = session.wait_for_notify(...)

注意这里不是轮询数据库,也不是 sleepwait_for_notify 是 openYuanrong Agent Session 的等待能力:当前执行线程/协程会挂起并释放会话锁,直到同一会话收到 notify 或等待超时。

notify(payload) 唤醒后,函数继续往下走,调用 Kimi 生成大纲,再等一次用户确认,确认后继续生成正文草稿,最后把结果写进 session histories:

outline = generate_outline(user_info)            # Kimi 生成大纲

_record(session, "confirm_outline", outline=outline,
        message="大纲已由 Kimi 生成,请确认是否继续生成文章草稿。")
confirmation = session.wait_for_notify(...)       # 再等一次确认

draft = generate_article(user_info, outline, confirmation)  # Kimi 生成草稿
_record(session, "done", outline=outline, draft=draft,
        message="文章草稿已由 Kimi 生成,openYuanrong Agent Session 流程完成。")

这个流程的价值在于:业务代码写起来像一段同步流程,但实际是跨请求、跨用户输入、多阶段恢复执行的。 Kimi 调用封装在 functions/llm_client.py,只负责按 prompt 生成大纲(JSON Mode)和草稿,不感知会话状态。

九、三次调用与会话亲和

端到端脚本 scripts/run_agent_session.sh 的核心是三次 HTTP 调用。

第一次:启动 Agent。它会进入 wait_for_notify() 等待,所以放到后台:

curl -sS -X POST "${FRONTEND_ENDPOINT}/serverless/v1/functions/${URN}/invocations" \
  -H "Content-Type: application/json" \
  -H "X-Instance-Session: ${SESSION_HEADER}" \
  --data-binary '{"action":"start","reset":true}' > "${LOG_DIR}/agent-start.response.json" &

第二次:提交选题信息唤醒 Agent。这个请求只负责把 payload 送进 Session,返回值只是“已通知”:

curl -sS -X POST ".../invocations" \
  -H "X-Instance-Session: ${SESSION_HEADER}" \
  --data-binary '{"action":"notify","payload":{"product":"AI Agent Session","audience":"想写补课文章的开发者","tone":"实操、少废话","pain":"普通函数请求结束就丢上下文"}}'

第三次:确认大纲,继续生成草稿。同样是通知请求,真正的草稿结果由还在等待的原始 start 请求继续执行后返回:

curl -sS -X POST ".../invocations" \
  -H "X-Instance-Session: ${SESSION_HEADER}" \
  --data-binary '{"action":"notify","payload":{"confirm":true}}'

三次请求都带同一个 Header:

X-Instance-Session: {"sessionID":"demo-agent-kimi-real-005","sessionTTL":0,"concurrency":2}

这就是 openYuanrong 会话调用的入口:sessionID 用来建立和命中会话绑定;只要绑定关系有效,后续相同 SessionID 的请求会被定向到同一实例。如果原实例不可用,新实例可以从分布式数据系统重新加载会话上下文(如 histories)。

请求打的不是 Web demo 自己的本地接口,而是 openYuanrong frontend:

http://192.168.2.6:8888/serverless/v1/functions/{URN}/invocations

在这里插入图片描述

十、端到端运行结果

CLI 流程跑通后,两次 notify 都成功,原始 start 请求返回 done
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

关键字段:

{
  "status": "done",
  "session_id": "demo-agent-kimi-real-005",
  "history_stages": [
    "collect_info", "info_received",
    "confirm_outline", "confirmation_received", "done"
  ]
}

这条 history_stages 证明同一个 SessionID 下的 histories 被连续读写,流程真实经历了 collect_info → info_received → confirm_outline → confirmation_received → done。这不是一次性模型调用,而是一个跨多次请求、依赖会话亲和与状态恢复的 Agent 执行流程。

对照官方多轮对话示例:

官方示例里的角色 本文 demo 里的角色
第一次 /invocations 请求 action=start
sess.wait(...) / session.wait_for_notify(...) 等待选题信息、等待大纲确认
第二次带相同 SessionID 的 notify 请求 action=notify,提交选题信息
再一次 notify 请求 action=notify,确认继续生成草稿
原始请求最终返回 start 请求返回 status=doneoutlinedraft 和 histories

十一、Web 控制台

为了让 demo 不只停留在命令行,加了一个零依赖 Web 控制台。

cd ~/openYuanrong-agent-demo/agent-demo
PORT=18080 bash scripts/start_web.sh
# 浏览器打开 http://192.168.2.6:18080

页面做三件事:启动 Agent、发送选题信息、确认大纲。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

页面本身不是核心,它只是展示层,背后仍然调用 openYuanrong frontend:8888:

response = requests.post(
    f"{FRONTEND_ENDPOINT}/serverless/v1/functions/{function_urn}/invocations",
    headers={"Content-Type": "application/json",
             "X-Instance-Session": _session_header(session_id)},
    json=payload, timeout=timeout)

在这里插入图片描述

换句话说,页面不是伪造状态,只是把请求转发给 openYuanrong。

十二、怎么证明这个 demo 真的用了 openYuanrong

很多 demo 讲得天花乱坠,最后其实只是本地 Python 调了一次模型。这个 demo 可以从 6 个角度证明它没有:

  1. 集群在运行yr health 输出里 frontend / meta_service / function_scheduler / function_agent 全部 RUNNING
  2. 函数注册在 openYuanrong:URN sn:cn:yrk:default:function:0@agentdemo@kimi-agent:latest
  3. 元数据里启用了 Agent Session:etcd 中 "enableAgentSession": true
  4. 调用走的是 frontendhttp://192.168.2.6:8888/serverless/v1/functions/{URN}/invocations
  5. 请求带了 Session HeaderX-Instance-Session: {"sessionID":"...","sessionTTL":0,...}
  6. 代码真实调用了 Agent Session APIload_session() / wait_for_notify() / notify() / histories 读写。

更关键的是:start 请求在 wait_for_notify() 处挂起后,后续两个带同一 SessionID 的 notify 请求把数据送回同一会话流程,最终由原始 start 请求返回 done。这些证据都成立,就说明它确实把 openYuanrong 放在了 Agent Runtime 的位置上。

十三、openYuanrong 和 Kimi 的职责边界

这个 demo 最值得讲的不是“调用了哪个模型”,而是职责边界清楚:

模块 负责什么 不负责什么
openYuanrong 函数注册、运行、会话加载、等待、唤醒、会话亲和、histories、状态恢复 生成文章内容
Kimi 根据 prompt 生成大纲和草稿 保存会话状态、等待用户、恢复执行
Web 控制台 展示状态、触发请求 不保存核心 Agent 状态
CLI 脚本 复现端到端流程 不替代 openYuanrong Runtime

一句话:

大模型不是 Agent 的全部。Agent 还需要一个能承载状态和执行流的 Runtime。

十四、结论

这次 demo 最终跑通了三件事:

  1. openYuanrong 函数服务真实运行,函数注册在 openYuanrong 里,并通过 openYuanrong frontend 调用。
  2. openYuanrong Agent Session 真实生效,函数内部使用 load_session / wait_for_notify() / notify() 和 histories 读写,完成两轮等待和唤醒。
  3. Kimi API 真实参与生成,先生成大纲,再在用户确认后生成草稿。

最终草稿也整理成了 Markdown 文件,方便后续修改和发布:
在这里插入图片描述
在这里插入图片描述

所以这个项目不是“页面套模型”,而是一次完整实操:

openYuanrong 负责运行时、会话、等待、唤醒;
Kimi 负责模型生成;
Web/CLI 负责触发和展示。

最值得强调的不是“我调用了 Kimi”,而是:

这个 demo 把一个需要多轮等待、外部唤醒和会话状态恢复的 Agent,真实部署到了 openYuanrong 函数运行时里,并用 Kimi 完成了生成任务。


参考文档

  1. openYuanrong AI Agent 多轮对话示例:https://docs.openYuanrong.org/zh-cn/latest/multi_language_function_programming_interface/examples/ai_agent_multiturn_dialogue.html
  2. openYuanrong AI Agent 会话与亲和性调度:https://docs.openYuanrong.org/zh-cn/latest/multi_language_function_programming_interface/advanced_tutorials/ai_agent_session.html
  3. openYuanrong 官方文档首页:https://docs.openYuanrong.org/zh-cn/latest/index.html
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐