11 · 智能体运行时
Experimental:智能体运行时、
ace-rpc跨进程、ace-autopilot处于0.1.0早期,API 可能演进。
ACE 内置一个轻量智能体(Agent)运行时,用于把「LLM + 工具调用循环」暴露为 HTTP 服务,也供框架自调度。核心在 ace-agent(import aceboot::agent.*)。
核心类型
public enum Role { | User | Assistant | System | ToolResult }
public class Message {
public let role: Role
public let content: String
public let tool: String // 仅 ToolResult 用,标识对应工具
public init(role: Role, content: String)
public init(role: Role, content: String, tool: String)
}
public enum LlmResponse {
| Text(String) // 最终文本答复
| ToolUse(String, String) // 请求调用工具:(工具名, 参数 JSON 字符串)
}
public interface LlmProvider { // 可插拔 LLM 抽象
func chat(messages: ArrayList<Message>, tools: ArrayList<Tool>): LlmResponse
}
public interface Tool { // 可调用工具
prop name: String
prop description: String
func call(args: String): String // 入参/出参均为 String
}
public class Agent {
public init(llm: LlmProvider, tools: ArrayList<Tool>, maxTurns!: Int64 = 8)
public func run(input: String): String
public func asHandler(): (Context) -> String
}
工具调用循环
Agent.run(input) 的循环(最多 maxTurns,默认 8 轮):
- 用当前对话历史调
llm.chat(messages, tools); - 返回
Text(t)→ 直接返回t(最终输出); - 返回
ToolUse(name, args)→ 按name匹配工具,把tool.call(args)结果作为ToolResult消息回填历史,进入下一轮;未知工具回填错误文本让 LLM 自愈(不抛异常); - 达到
maxTurns仍无Text→ 返回"[ace-agent] max turns reached"。
把 Agent 暴露为 HTTP 服务
package my_app
import aceboot::framework.*
import aceboot::framework_macros.*
import aceboot::framework_boot.*
import aceboot::agent.*
import std.collection.*
// 1) 实现 LlmProvider(这里是 mock;接真实 LLM 见下)
class EchoLlm <: LlmProvider {
public func chat(messages: ArrayList<Message>, tools: ArrayList<Tool>): LlmResponse {
Text("agent says: ${messages[0].content}")
}
}
// 2) 实现工具
class AddTool <: Tool {
public prop name: String { get() { "add" } }
public prop description: String { get() { "add two ints from 'a,b'" } }
public func call(args: String): String {
let p = args.split(",")
"${Int64.parse(p[0]) + Int64.parse(p[1])}"
}
}
// 3) 构造 Agent(顶层单例)
let tools = ArrayList<Tool>()
let chatAgent = Agent(EchoLlm(), tools) // tools.add(AddTool()) 注册工具
// 4) 控制器暴露
@Controller["/chat"]
public class ChatController {
@Post["/"]
public func ask(body: String): String {
chatAgent.run(body)
}
}
main(): Int64 { AceApplication.run("127.0.0.1", 8080); return 0 }
也可用 chatAgent.asHandler() 直接得到一个 (Context) -> String 处理器(输入取 rawBody,回退 ?q=)。
接入真实 LLM(Claude)
ace-agent-claude(import aceboot::agent_claude.*)把 ace-agent 对话模型翻译为 Anthropic Messages API 报文。它是纯函数、stdx-free,真实 HTTP 发送以注入方式外置:
public type ClaudeTransport = (String) -> LlmResponse // 注入:发送请求报文 → 解析返回
public class ClaudeProvider <: LlmProvider {
public init(
transport: ClaudeTransport,
model!: String = "claude-opus-4-8",
maxTokens!: Int64 = 1024,
system!: String = ""
)
// chat() 内部:buildMessagesRequest(...) 构造报文 → transport(req) → LlmResponse
}
// 报文构造(纯函数,可单测):
buildMessagesRequest(model, maxTokens, system, messages, tools): String
接线:在 boot/example 层实现一个 ClaudeTransport——用 stdx.net.http POST /v1/messages(带 x-api-key,从环境注入、勿硬编码;anthropic-version 头),用 stdx.encoding.json 解析 content[0](text → Text、tool_use → ToolUse(name, input)),再把 ClaudeProvider(transport) 传给 Agent。
仓库只提供报文构造与适配器骨架,未内置真实 HTTP transport(它是注入点)。当前工具的
input_schema恒为{"type":"object"},无逐参数 schema。
ace-rpc:单体/微服务透明切换
业务面向接口编程;提供本地实现(进程内直调)与远程代理(经 Transport.send 转发)两种实现,装配处绑定哪个即在单体/微服务间切换,业务零改动。
public interface Transport {
func send(service: String, method: String, payload: String): String
}
public class InProcessTransport <: Transport { // 进程内传输(单体/测试)
public func register(service: String, handler: (String, String) -> String): Unit
public func send(service: String, method: String, payload: String): String
}
跨网络 HTTP transport 标注「后续补」,当前仅进程内。
ace-autopilot:分级护栏控制面
一个安全控制面——智能体只「提议」调参,执行边界由分级护栏强制(安全不交给模型):
public enum KnobTier { | Whitelist | Dangerous }
public enum Decision { | Applied(String, Float64) | Proposed(String, Float64) | Rejected(String, String) }
public class Autopilot {
public init(autoExecuteWhitelist!: Bool = true)
public func registerKnob(k: Knob): Unit
public func propose(name: String, value: Float64): Decision // 钳制到[min,max]→按分级 Applied/Proposed→审计
public func observeErrorRate(knobName, errorRate, threshold): ?Decision // metrics→决策闭环示例
public func auditLog(): Array<String>
}
Whitelist 旋钮自动执行,Dangerous 永远只建议(需人工确认),未知旋钮拒绝;所有决策入审计日志。
下一章:测试与部署。