LLM 简介
LLM 简介
Section titled “LLM 简介”此页面面向 AI 代理和 LLM。如果你基于 Wippy 进行构建或为 Wippy 项目生成代码,请先阅读本页。
Wippy 是什么
Section titled “Wippy 是什么”Wippy 是一个基于 Actor 模型构建的单二进制应用运行时。它在隔离的进程中运行 Lua 代码,并通过消息传递进行通信——没有共享内存,也没有锁。存在三种计算模型:函数(无状态,请求级作用域)、进程(带状态的长期 Actor)和工作流(由 Temporal 支持的持久 Actor,能够在崩溃后存活)。系统的设计使得代理可以生成代码、注册它,并在不重新部署的情况下改进应用。
Wippy 中的一切都是注册表条目(registry entry)。条目具有 ID(namespace:name)、种类(决定行为)、元数据和数据。YAML 文件是声明条目的一种方式,但注册表才是运行时的真实来源,条目可以在系统运行时被创建、更新或删除。
种类决定了条目的行为:
function.lua— 无状态可调用函数process.lua— 长期运行的 Actorworkflow.lua— 持久工作流(Temporal)http.service— HTTP 服务器http.router— 带中间件的路由组http.endpoint— HTTP 处理器db.sql.postgres/mysql/sqlite— 数据库连接store.memory/store.sql— 键值存储queue.queue— 消息队列process.host— 进程执行主机process.service— 受监督的进程contract.definition/contract.binding— 类型化服务接口registry.entry— 配置数据
myapp/├── .wippy.yaml # Runtime configuration├── wippy.lock # Source directories└── src/ ├── _index.yaml # Entry definitions (namespace: app) ├── api/ │ ├── _index.yaml # namespace: app.api │ └── handler.lua └── workers/ ├── _index.yaml # namespace: app.workers └── task.lua条目定义位于 _index.yaml 文件中:
version: "1.0"namespace: app.api
entries: - name: get_user kind: function.lua source: file://handler.lua method: get_user modules: [sql, json]
- name: get_user.endpoint kind: http.endpoint meta: router: app:api_router method: GET path: /users/{id} func: app.api:get_user函数是无状态的。它们接收参数、执行工作并返回结果。它们继承调用者的上下文,并在调用者取消时被取消。
local sql = require("sql")local json = require("json")local http = require("http")
local function get_user(id) local db, err = sql.get("app:main_db") if err then return nil, err end
local rows, err = db:query("SELECT * FROM users WHERE id = $1", id) if err then return nil, err end if #rows == 0 then return nil, errors.new(errors.NOT_FOUND, "user not found") end
return rows[1]end
return get_user对于 HTTP 处理器,使用 http 模块:
local http = require("http")local json = require("json")
local function handler() local req = http.request() local res = http.response()
local id = req:param("id") local user, err = funcs.call("app.api:get_user", id) if err then res:set_status(404) res:write_json({error = err:message()}) return end
res:write_json(user)end
return handler进程是 Actor。它们拥有自己的 PID,通过收件箱接收消息,并在消息之间保持状态。它们在阻塞 I/O 时让出执行,从而允许数千个进程并发运行。
local function worker(initial_config) local inbox = process.inbox() local events = process.events()
while true do local r = channel.select { inbox:case_receive(), events:case_receive() }
if r.channel == events then local ev = r.value if ev.type == process.event.CANCEL then break end elseif r.channel == inbox then local msg = r.value local topic = msg:topic() local data = msg:payload():data() handle_message(topic, data) end endend
return worker从其他代码中生成进程:
local pid = process.spawn("app.workers:task", "app:process_host", config)process.send(pid, "work", {item_id = 123})工作流是持久的——它们可以在崩溃和重启后存活。代码看起来像普通的 Lua。运行时会自动记录函数调用结果、休眠和随机值,以使重放具有确定性。
local function order_flow(order) local inventory = funcs.call("app:reserve_inventory", order.items) if not inventory then return nil, errors.new("out of stock") end
local payment = funcs.call("app:charge_payment", order.total) if not payment then funcs.call("app:release_inventory", inventory.id) return nil, errors.new("payment failed") end
-- Wait for approval signal (can block for days) local msg = process.inbox():receive() if not msg:payload():data().approved then funcs.call("app:refund_payment", payment.id) funcs.call("app:release_inventory", inventory.id) return nil, errors.new("rejected") end
return funcs.call("app:fulfill_order", order.id)end
return order_flow关键 API
Section titled “关键 API”local funcs = require("funcs")
-- Synchronouslocal result, err = funcs.call("namespace:function_name", arg1, arg2)
-- Asynchronous (returns Future)local future = funcs.async("namespace:function_name", arg1)local result, err = future:result()
-- With contextlocal exec = funcs.new():with_context({user_id = "123"})exec:call("namespace:function_name")-- Send message (fire-and-forget)process.send(pid, "topic", data)
-- Receive messageslocal inbox = process.inbox()local msg, ok = inbox:receive()local topic = msg:topic()local data = msg:payload():data()
-- Monitor another process (receive EXIT on death)process.monitor(pid)
-- Link processes (bidirectional failure notification)process.spawn_linked("namespace:name", "host")用于协程通信的 Go 风格通道:
local ch = channel.new(10) -- bufferedch:send(value)local val, ok = ch:receive()
-- Select on multiple channelslocal r = channel.select { ch1:case_receive(), ch2:case_receive(), timeout:case_receive()}函数返回 result, error 对。错误是类型化对象:
local result, err = some_operation()if err then if errors.is(err, errors.NOT_FOUND) then -- handle not found end return nil, errors.wrap(err, "context message")end错误种类:UNKNOWN、INVALID、NOT_FOUND、ALREADY_EXISTS、PERMISSION_DENIED、TIMEOUT、CANCELED、UNAVAILABLE、INTERNAL、CONFLICT、RATE_LIMITED。
-- SQLlocal sql = require("sql")local db = sql.get("app:main_db")local rows, err = db:query("SELECT * FROM users WHERE active = $1", true)db:execute("INSERT INTO users (name) VALUES ($1)", name)
-- Key-value storelocal store = require("store")local cache = store.get("app:cache")cache:set("key", value, 3600) -- TTL in secondslocal val = cache:get("key")
-- Queuelocal queue = require("queue")queue.publish("app:tasks", {task = "process", id = 123})
-- Filesystemlocal fs = require("fs")local vol = fs.get("app:storage")local data = vol:readfile("path/to/file.txt")vol:writefile("output.txt", content)HTTP 客户端
Section titled “HTTP 客户端”local http_client = require("http_client")
local resp, err = http_client.get("https://api.example.com/data", { headers = {Authorization = "Bearer token"}, timeout = "10s"})local body = resp.bodylocal security = require("security")
local actor = security.actor() -- who is callinglocal scope = security.scope() -- what permissions applylocal allowed = security.can("read", "resource:users")
-- Token managementlocal ts = security.token_store("app:tokens")local token = ts:create(actor, scope, {expiration = "24h"})local validated_actor, validated_scope = ts:validate(token)local time = require("time")
time.sleep("5s")local now = time.now()local timeout = time.after("30s") -- channel that fires oncelocal ticker = time.ticker("10s") -- repeating channellocal registry = require("registry")
local entry = registry.get("app.api:get_user")local tests = registry.find({["meta.type"] = "test"})
-- Create entries at runtimelocal snap = registry.snapshot()local changes = snap:changes()changes:create({id = "app:new_func", kind = "function.lua", data = {...}})changes:apply()local events = require("events")
-- Publishevents.send("orders", "order.created", "/orders/123", {order_id = "123"})
-- Subscribe (wildcards supported)local sub = events.subscribe("orders.*")local ch = sub:channel()local evt = ch:receive()模块访问控制
Section titled “模块访问控制”每个条目声明它可以 require() 哪些模块。未列出的模块根本不可用——除非你显式授予,否则不存在 os.execute、io.open、debug.* 或 package.*。运行时不会扫描或验证源代码;它在模块级别控制访问。如果一个模块不在列表中,那么对于该条目而言它就不存在。
modules: [sql, json, http, time, funcs, store]这也是工作流确定性的工作原理——工作流条目仅接收确定性模块。运行时在模块级别拦截 time.now()、uuid.v4() 和其他非确定性调用,记录结果以供重放。
Wippy 有通过依赖安装的框架模块:
- wippy/llm — LLM 集成(OpenAI、Anthropic、Google)。
llm.generate()、结构化输出、嵌入、流式传输。 - wippy/agent — 带工具使用、委派、特性、记忆的代理框架。代理定义为注册表条目。
- wippy/test — BDD 测试。
describe/it块、断言、模拟。 - wippy/dataflow — 基于 DAG 的工作流编排。Function、Agent、Cycle、Parallel 节点。
- wippy/relay — 带中央 Hub、按用户 Hub、插件路由的 WebSocket 中继。
- wippy/views — 带模板渲染的页面和组件系统。
- wippy/facade — 带身份验证桥接的前端 iframe 外观。
- 条目 ID 使用
namespace:name格式 - 名称使用点进行语义分隔,使用下划线分隔单词:
get_user.endpoint - 函数返回
result, error——始终检查错误 - 进程通过消息传递进行通信,从不共享状态
- 使用
channel.select多路复用多个事件源 - 监督树处理失败——按”let it crash”原则设计
- 上下文(trace ID、用户信息、安全性)自动通过函数调用传播
- 工作流不能直接使用非确定性操作——运行时为
funcs.call、time.sleep、uuid.v4、time.now处理此问题
完整文档可在 wippy.ai/docs 获取。对 LLM 友好的端点:
- 浏览结构:
https://wippy.ai/llm/toc - 搜索:
https://wippy.ai/llm/search?q=query - 获取页面:
https://wippy.ai/llm/path/en/<path> - 批量获取:
https://wippy.ai/llm/context?paths=path1,path2