From 998f2348ede28971829a7512f810e00dd10275ac Mon Sep 17 00:00:00 2001 From: xiayu Date: Wed, 10 Jun 2026 06:58:36 +0800 Subject: [PATCH 01/20] docs: position ksadk as runtime platform --- CHANGELOG.md | 27 +- Makefile | 2 +- README.en.md | 210 +++++++++----- README.md | 211 ++++++++++----- README.zh-CN.md | 211 ++++++++++----- ksadk/__init__.py | 4 +- ksadk/version.py | 2 +- mkdocs.yml | 85 +++--- .../getting-started/configuration.en.md | 2 +- public-docs/getting-started/configuration.md | 2 +- public-docs/guides/runtime-products.en.md | 3 +- public-docs/guides/runtime-products.md | 3 +- public-docs/index.en.md | 256 +++++++++--------- public-docs/index.md | 251 ++++++++--------- pyproject.toml | 4 +- tests/test_public_positioning_docs.py | 172 ++++++++++++ uv.lock | 2 +- 17 files changed, 940 insertions(+), 507 deletions(-) create mode 100644 tests/test_public_positioning_docs.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fd89be4..76833ce3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,29 @@ # 更新日志 -本文件记录 **Kingsoft AgentEngine SDK (ksadk)** 的重要变更。 +本文件记录 **KsADK Agent Runtime Platform** 的重要变更。 格式参考 [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 版本遵循 [Semantic Versioning](https://semver.org/spec/v2.0.0.html)。 +## [0.6.4] - Unreleased + +### 亮点 + +- **公开定位重构**:将项目首页、README 和文档首页从普通 SDK 口径调整为 Agent Runtime Platform,补齐 Why KsADK、30 秒体验、架构图、对比表、Deployment、Observability 和 Community。 +- **文档信息架构调整**:MkDocs 导航改为 Getting Started / Build / Run / Deploy / Observe / Extend / Reference,更贴近开发者完成任务的路径。 +- **Samples 场景入口对齐**:`ksadk-samples` 根 README 改为场景优先,真实映射 Knowledge Assistant、Workflow Agent、Tool-Using Agent 和 Memory-aware Agent;尚未实现的场景只进入 Roadmap。 +- **公开元数据修复**:更新 PyPI summary 和包内简介为 Agent Runtime Platform 定位,为后续补丁发布准备干净的 long description。 + +### 修复 + +- 清理 README、CHANGELOG、文档首页和 runtime product 文档中的环境特定表述,避免公开页面出现内部环境名、内部 header 或私有 endpoint 示例。 +- 将公开定位、敏感词扫描和 README 场景入口要求纳入本地门禁,降低后续发布材料回退风险。 + +### 发布说明 + +- 这是修复 0.6.3 公开页面和 PyPI 元数据口径的补丁版本草案;已发布到 PyPI 的 0.6.3 元数据不可覆盖,因此后续需要通过新版本修复。 +- 0.6.4 在用户 review 通过前不创建 tag、不发布 GitHub Release,也不上传 PyPI。 + ## [0.6.3] - 2026-06-09 ### 亮点 @@ -17,7 +36,7 @@ ### 修复 - 修复 LangGraph runner 在工具调用后没有文本流式 chunk 时不会输出最终 answer,导致本地 Web UI 存储空 assistant message 的问题。 -- 修复 Skill Service KOP client 在 `KSADK_SKILL_SERVICE_REGION=pre-online` 下没有按 AgentEngine client 规则设置 `X-Ksc-Region: cn-beijing-6` 和 `X-KSC-CUSTOM-SOURCE: pre` 的问题。 +- 修复 Skill Service KOP/AICP client 在环境化路由下没有按 AgentEngine client 规则映射 region 与必要请求头的问题。 - 修复内置工具 dispatcher 遇到未知 include/tool name 时可能抛异常的问题,现在返回结构化 `unknown_tool` 错误,便于 Agent 继续解释。 - 修复 OpenClaw / Hermes deploy update payload 默认携带 `env_vars`、`storage`、`network` 等配置组的问题,降低客户更新公共镜像时误改生产配置的风险。 @@ -122,7 +141,7 @@ - 修复 Responses `input_file.file_data` / `file_url` 在会话回放中无法还原为附件展示的问题。 - 修复 conversation runtime 落库时只保存 display 文本和附件提示,导致刷新后图片变成纯文本占位的问题。 - 修复 Hosted UI 回放事件时未识别 Responses `input_file.file_data` / `input_file.file_url` 的问题。 -- 修复 server responses session mirror 在 `account_id` 为空或 PostgreSQL duplicate session 错误文本变化时可能失败,导致预发 Hosted UI 上传图片后报“连接断开或生成出错”的问题。 +- 修复 server responses session mirror 在 `account_id` 为空或 PostgreSQL duplicate session 错误文本变化时可能失败,导致 Hosted UI 上传图片后报“连接断开或生成出错”的问题。 - 修复刷新正在流式输出的会话时,订阅增量事件被单独构建成多条空“思考过程”消息的问题;恢复路径现在先合并完整 session events,再重建消息列表。 - 修复会话列表重复项、活动 invocation 判定过早失效、运行中会话锁住其他 session 切换等 UI 状态问题。 - 修复 Workspace 文件列表自动刷新时把当前 Markdown/HTML/文本预览强制切回编辑态的问题。 @@ -502,7 +521,7 @@ - 修复 Windows 离线安装时核心依赖缺失的问题。 - 修复 Windows BOM 文件兼容性,统一按 `utf-8-sig` 读取配置。 - 修复 Web UI 构建阶段 Google Fonts 资源导致的失败问题。 -- 修复预发与生产 serverless 客户端的环境路由问题。 +- 修复多环境 serverless 客户端的路由选择问题。 - 为 `fastapi` 与 `pydantic` 增加兼容性版本上限约束。 ## [0.1.0] - 2026-01-15 diff --git a/Makefile b/Makefile index db2a6012..232959ee 100644 --- a/Makefile +++ b/Makefile @@ -282,7 +282,7 @@ public-audit: public-secret-audit public-test: @echo "==> public tests" - @uv run --extra dev pytest tests/test_open_source_audit.py tests/test_prepare_ksadk_python_export.py tests/test_prepare_ksadk_web_export.py tests/test_runtime_common_packaging.py tests/test_tracing_setup_otlp.py -q + @uv run --extra dev pytest tests/test_open_source_audit.py tests/test_public_positioning_docs.py tests/test_prepare_ksadk_python_export.py tests/test_prepare_ksadk_web_export.py tests/test_runtime_common_packaging.py tests/test_tracing_setup_otlp.py -q public-build-check: clean-dist @echo "==> build and twine check" diff --git a/README.en.md b/README.en.md index b7b5b64b..9cf10d2a 100644 --- a/README.en.md +++ b/README.en.md @@ -1,108 +1,188 @@ -# ksadk +# KsADK [简体中文](README.md) | [English](README.en.md) [![zread](https://img.shields.io/badge/Ask_Zread-_.svg?style=flat&color=00b0aa&labelColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTg0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTg0IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjc1ODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDQiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L3N2Zz4K&logoColor=ffffff)](https://zread.ai/kingsoftcloud/ksadk-python) -Kingsoft Cloud Agent Development Kit. `ksadk` provides the Python SDK and command line tools for building, running, packaging, and deploying AgentEngine agents. After installation, both `agentengine` and the equivalent `ksadk` command are available. KsADK covers local development, serverless runtime, ADK, LangChain/LangGraph, DeepAgents, Hermes, OpenClaw, MCP, and Skill Runtime scenarios. +Build agents once. Run them anywhere. -Current version: `0.6.3`. +KsADK is the Agent Runtime Platform for AI agents. Build with Google ADK, LangGraph, LangChain, or DeepAgents, then run, debug, expose, observe, and deploy those agents through one runtime experience. -## Install +Current version: `0.6.4`. -```bash -pip install -U ksadk -``` +- Local Development +- Browser Debugging UI +- OpenAI-Compatible API +- Unified Runtime +- Sandbox Execution +- Serverless Deployment +- Hermes & OpenClaw Runtime + +## Why KsADK + +Most agent frameworks solve agent development. + +KsADK solves agent runtime. + +It does not replace your framework. It provides the unified platform layer for: -Install optional runtime extras when needed: +- Development: one CLI for project creation, configuration, and local runs. +- Debugging: browser UI, sessions, attachments, workspace files, and streaming output. +- Runtime: framework runners, OpenAI-Compatible APIs, and consistent invocation. +- Sandbox: Skill Runtime, Workspace, and isolated sandbox backend boundaries. +- Deployment: Serverless, Hermes, OpenClaw, and remote AgentEngine entrypoints. +- Observability: OpenTelemetry-first tracing for multiple backends. + +Keep using your preferred framework. Get a complete runtime platform. + +## 30 Seconds Quick Start ```bash -pip install -U "ksadk[adk]" -pip install -U "ksadk[langgraph]" -pip install -U "ksadk[deepagents]" -pip install -U "ksadk[skills]" +python -m venv .venv +source .venv/bin/activate pip install -U "ksadk[all]" + +agentengine init demo-agent -f langgraph +cd demo-agent +agentengine config set OPENAI_API_KEY=your-api-key OPENAI_MODEL_NAME=gpt-4o-mini +agentengine run -i ``` -## Quick Start +Open the local browser debugging UI: -The examples below use `agentengine`; you can replace it with `ksadk` for the same CLI. +```bash +agentengine web . --no-open +``` -Create and run a local agent: +If your model provider is not the default OpenAI endpoint, also set: ```bash -agentengine init my-agent -f langgraph -cd my-agent -agentengine config -agentengine run -i +agentengine config set OPENAI_BASE_URL=https://api.example.com/v1 ``` -Deploy to AgentEngine serverless runtime: +## Architecture + +```mermaid +flowchart TD + Code["Agent Code
ADK / LangGraph / LangChain / DeepAgents"] --> SDK["KsADK SDK
runner adapters + config"] + SDK --> Runtime["Unified Runtime
CLI + Web UI + OpenAI-Compatible API"] + Runtime --> Sandbox["Sandbox
isolated command/code execution"] + Runtime --> Skills["Skills
Skill Space + Skill Runtime"] + Runtime --> Memory["Memory & Knowledge
sessions + LTM + RAG"] + Sandbox --> Engine["AgentEngine"] + Skills --> Engine + Memory --> Engine + Engine --> Backends["Serverless / Hermes / OpenClaw Runtime"] +``` + +## Supported Frameworks + +| Framework | What KsADK adds | +| --- | --- | +| Google ADK | Templates, runner adapter, local runtime, Web UI debugging, and deployment entrypoints. | +| LangGraph | Graph-state entrypoint, tool calling, streaming, Skill Runtime, and workspace toolsets. | +| LangChain | Runnable/chain adaptation, local OpenAI-Compatible APIs, and tracing. | +| DeepAgents | Project entrypoint, runtime wrapping, browser debugging, and deployment artifacts. | + +## Comparison + +| Capability | ADK | LangGraph | OpenAI Agents SDK | KsADK | +| --- | --- | --- | --- | --- | +| Agent Development | Yes | Yes | Yes | Yes | +| Browser Debugging UI | No | No | No | Yes | +| Unified CLI | No | No | No | Yes | +| OpenAI Compatible API | No | No | Partial | Yes | +| Sandbox Runtime | No | No | No | Yes | +| Deployment Workflow | No | No | No | Yes | +| Multi Runtime Backend | No | No | No | Yes | + +This table compares unified runtime-platform capabilities provided by the project itself. KsADK is designed to complement agent frameworks, not replace them. + +## Core Capabilities + +- `agentengine init`: create or import an agent project. +- `agentengine config`: manage `.env` and `agentengine.yaml`. +- `agentengine run`: run and debug locally from the terminal. +- `agentengine web`: start the local Web UI for streaming, attachments, workspace files, tools, and sessions. +- `/v1/responses` and `/v1/chat/completions`: expose OpenAI-Compatible APIs. +- `ksadk.toolsets`: built-in Skill, Workspace, Platform, and Sandbox tools. +- Skill Runtime: discover, download, verify, load, and execute Skill workflows. +- Sandbox Runtime: execute commands or code through a configured isolated backend. +- Hermes & OpenClaw: runtime backends for fuller deployment scenarios. + +## Examples + +The samples repository is organized by scenario, not only by framework: + +- [KSADK Samples](https://github.com/kingsoftcloud/ksadk-samples) +- Knowledge Assistant: RAG and knowledge-base QA. +- Workflow Agent: LangGraph plus AgentEngine toolsets. +- Tool-Using Agent: custom business tools. +- Memory-aware Agent: short-term and long-term memory patterns. + +Every public demo should include a Chinese-first README, run commands, environment-variable guidance, fallback behavior, and verification prompts. + +## Deployment + +KsADK is local-first, with reviewed deployment entrypoints when you are ready: ```bash +agentengine build . agentengine launch . --target serverless +agentengine dashboard open ``` -Open the hosted dashboard: +When updating existing Hermes or OpenClaw instances, KsADK preserves server-side env, storage, network, and memory configuration by default. Those groups are overwritten only when matching CLI options are provided explicitly. + +## Observability + +KsADK is OpenTelemetry-native. + +Prefer standard OTLP environment variables: ```bash -agentengine dashboard open +OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.example.com +OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer%20token ``` -## What Is Included +Compatible with: -- Local development commands: `init`, `config`, `run`, `web` -- Build and deploy commands: `build`, `deploy`, `launch` -- Remote operations: `agent invoke`, `files`, `dashboard` -- Runtime integrations: ADK, LangChain, LangGraph, DeepAgents, MCP -- Hosted runtime assets: Hermes and OpenClaw -- Skill Runtime: Skill Space discovery, zip download, `sha256` verification, safe extraction, instruction loading, and workflow execution through `local_process` or E2B sandbox backends -- Built-in AgentEngine tools: skill discovery/loading, workspace file operations, component status, sandbox status, and sandbox direct code/command execution -- Sandbox Runtime: common sandbox abstraction with an E2B-compatible backend +- Langfuse +- Arize +- Datadog +- Grafana +- Phoenix -## 0.6.3 Highlights +Export once. Observe anywhere. -- Hosted UI links align with the latest gateway / server `/hosted-ui/chat/`, share link, SSE subscription, and native terminal proxy contracts; `agentengine dashboard open` keeps using hosted entrypoints while `agentengine web` stays focused on local debugging. -- LangGraph runner now emits the final answer after tool calls even when the model does not stream text chunks, avoiding empty assistant messages in the local Web UI. -- Skill Service supports `KSADK_SKILL_SERVICE_REGION=pre-online` KOP routing with the expected pre-online headers. -- OpenClaw and Hermes updates preserve existing server-side env, storage, network, and memory configuration by default, and only overwrite those groups when matching CLI options are supplied explicitly. -- `ksadk.toolsets`, Tool Gateway, Skill Runtime, and Skill Service files are included in the package so the recommended LangGraph demo works after a clean install. +## 0.6.4 Highlights -## 0.6.2 Highlights +- Reposition public messaging from a generic SDK to an Agent Runtime Platform, with Why KsADK, a 30-second quick start, architecture, comparison, deployment, observability, and community sections. +- Rework the docs homepage and MkDocs navigation around Getting Started / Build / Run / Deploy / Observe / Extend / Reference. +- Remove environment-specific wording from README, CHANGELOG, docs, and future PyPI metadata so public pages do not expose internal environment names or internal headers. +- Add public-positioning and sensitive-word regressions to `public-preflight`. -- Skill Runtime can discover Skill Space entries, download and verify skill packages, load `SKILL.md`, and execute workflow-style skills through `local_process` or E2B sandbox backends. -- `ksadk.toolsets` provides Skill, Workspace, Platform, and Sandbox built-in tools; the recommended binding pattern is `get_agentengine_tools(include=["focused", "agentengine_tool_dispatcher"])`, with lower-frequency or higher-risk tools called through dispatcher `list` / `describe` / `call`. -- Tool Gateway provides a shared `approval_required` envelope for medium/high-risk operations such as workspace writes/deletes, Skill Runtime execution, and sandbox command/code execution. -- Workspace tools now include exact snippet editing and lightweight lint checks; Sandbox tools add direct `run_command` / `run_code` and only execute through the configured isolated sandbox backend. -- `setup_tracing()` now prefers standard `OTEL_EXPORTER_OTLP_*` HTTP traces configuration while existing Langfuse environment variables remain compatible. -- The environment registry and public docs cover OTLP traces, AICP endpoint mode, Skill Service endpoint/scheme overrides, Sandbox Runtime, Skill Runtime, and Tool Gateway settings. - -## Documentation +## 0.6.3 Highlights -The public documentation site is hosted on GitHub Pages: +- Hosted UI links align with the latest gateway / server contract, including `/hosted-ui/chat/`, share links, SSE subscription, and native terminal proxying. +- LangGraph runner emits a final answer after tool calls even when the model does not stream text chunks. +- Skill Service routing can be configured through environment variables for service URL, region, and required request-header mapping. +- OpenClaw and Hermes updates preserve existing server-side env, storage, network, and memory configuration by default. +- `ksadk.toolsets`, Tool Gateway, Skill Runtime, and Skill Service files are included in the package so the recommended LangGraph demo works after a clean install. -- [Documentation](https://kingsoftcloud.github.io/ksadk-python/en/) -- [中文文档](https://kingsoftcloud.github.io/ksadk-python/zh/) -- [Quickstart](https://kingsoftcloud.github.io/ksadk-python/en/getting-started/quickstart/) -- [Configuration](https://kingsoftcloud.github.io/ksadk-python/en/getting-started/configuration/) -- [CLI Reference](https://kingsoftcloud.github.io/ksadk-python/en/reference/cli/) -- [OpenAI-compatible API](https://kingsoftcloud.github.io/ksadk-python/en/reference/openai-compatible-api/) -- [Contributing](https://github.com/kingsoftcloud/ksadk-python/blob/main/CONTRIBUTING.md) -- [Security Policy](https://github.com/kingsoftcloud/ksadk-python/blob/main/SECURITY.md) +## Documentation -The site is built with MkDocs Material, matching the documentation stack used -by Google ADK and Volcengine VEADK. +- Documentation: +- 中文文档: +- English documentation: +- CLI reference: +- OpenAI-Compatible API: -## Project Links +## Community -- Documentation: - Repository: +- Wiki: - Samples repository: - Web UI repository: - PyPI: - -## Notes - -- Skill registration, CRUD, and version governance belong to Skill Service. `ksadk` consumes Skill Center at runtime. -- Sandbox template and instance lifecycle belong to Sandbox Service. `ksadk` uses the configured sandbox backend to execute runtime workflows. -- E2B-compatible sandbox backend uses the native `E2B_API_URL` and `E2B_API_KEY` environment variables. +- License: Apache-2.0 diff --git a/README.md b/README.md index 1ea8b03a..5720ba56 100644 --- a/README.md +++ b/README.md @@ -1,111 +1,188 @@ -# ksadk +# KsADK [简体中文](README.md) | [English](README.en.md) [![zread](https://img.shields.io/badge/Ask_Zread-_.svg?style=flat&color=00b0aa&labelColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTg0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTg0IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjc1ODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDQiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L3N2Zz4K&logoColor=ffffff)](https://zread.ai/kingsoftcloud/ksadk-python) -金山云 Agent Development Kit。`ksadk` 提供 Python SDK 和命令行, -安装后可使用 `agentengine` 或等价的 `ksadk` 命令创建、运行、调试、 -打包和部署 AgentEngine 智能体项目。它面向 -本地开发、Serverless 运行时、Google ADK、LangChain/LangGraph、 -DeepAgents、Hermes、OpenClaw、MCP 和 Skill Runtime 等场景。 +Build agents once. Run them anywhere. -当前版本:`0.6.3`。 +KsADK is the Agent Runtime Platform for AI agents. 你可以继续使用 Google ADK、LangGraph、LangChain 或 DeepAgents 编写业务 Agent,再用 KsADK 获得统一的本地运行、浏览器调试、OpenAI-Compatible API、沙箱执行、部署和可观测体验。 -## 安装 +当前版本:`0.6.4`。 -```bash -pip install -U ksadk -``` +- Local Development +- Browser Debugging UI +- OpenAI-Compatible API +- Unified Runtime +- Sandbox Execution +- Serverless Deployment +- Hermes & OpenClaw Runtime -按需安装可选运行时依赖: +## Why KsADK -```bash -pip install -U "ksadk[adk]" -pip install -U "ksadk[langgraph]" -pip install -U "ksadk[deepagents]" -pip install -U "ksadk[skills]" -pip install -U "ksadk[all]" -``` +Most agent frameworks solve agent development. -## 快速开始 +KsADK solves agent runtime. -以下示例使用 `agentengine`;所有命令也可以把 `agentengine` 替换为 `ksadk`。 +它不替换你的框架,而是在框架之上补齐运行时平台层: -创建并运行一个本地 Agent: +- Development:统一 `agentengine init`、`agentengine config`、`agentengine run`。 +- Debugging:本地 Web UI、会话、附件、workspace 文件和流式输出。 +- Runtime:统一 Runner、OpenAI-Compatible API 和多框架入口。 +- Sandbox:Skill Runtime、Workspace 和 sandbox backend 的隔离执行边界。 +- Deployment:Serverless、Hermes、OpenClaw 和远端 AgentEngine 入口。 +- Observability:OpenTelemetry-first tracing,可对接多种观测后端。 + +Keep using your preferred framework. Get a complete runtime platform. + +## 30 秒快速体验 ```bash -agentengine init my-agent -f langgraph -cd my-agent -agentengine config +python -m venv .venv +source .venv/bin/activate +pip install -U "ksadk[all]" + +agentengine init demo-agent -f langgraph +cd demo-agent +agentengine config set OPENAI_API_KEY=your-api-key OPENAI_MODEL_NAME=gpt-4o-mini agentengine run -i ``` -打开本地 Web UI: +打开本地浏览器调试界面: ```bash agentengine web . --no-open ``` -如需走部署形态,先使用 dry-run 或内部审核流程确认配置: +如果你的模型服务不是默认 OpenAI endpoint,再额外配置: + +```bash +agentengine config set OPENAI_BASE_URL=https://api.example.com/v1 +``` + +## Architecture + +```mermaid +flowchart TD + Code["Agent Code
ADK / LangGraph / LangChain / DeepAgents"] --> SDK["KsADK SDK
runner adapters + config"] + SDK --> Runtime["Unified Runtime
CLI + Web UI + OpenAI-Compatible API"] + Runtime --> Sandbox["Sandbox
isolated command/code execution"] + Runtime --> Skills["Skills
Skill Space + Skill Runtime"] + Runtime --> Memory["Memory & Knowledge
sessions + LTM + RAG"] + Sandbox --> Engine["AgentEngine"] + Skills --> Engine + Memory --> Engine + Engine --> Backends["Serverless / Hermes / OpenClaw Runtime"] +``` + +## Supported Frameworks + +| Framework | KsADK 负责什么 | +| --- | --- | +| Google ADK | 项目模板、Runner 适配、本地运行、Web UI 调试和部署入口。 | +| LangGraph | 图状态入口、工具调用、streaming、Skill Runtime 和 workspace toolsets。 | +| LangChain | Runnable/chain 适配、本地 OpenAI-Compatible API 和 tracing。 | +| DeepAgents | 项目入口、运行时包装、浏览器调试和部署制品。 | + +## Comparison + +| Capability | ADK | LangGraph | OpenAI Agents SDK | KsADK | +| --- | --- | --- | --- | --- | +| Agent Development | Yes | Yes | Yes | Yes | +| Browser Debugging UI | No | No | No | Yes | +| Unified CLI | No | No | No | Yes | +| OpenAI Compatible API | No | No | Partial | Yes | +| Sandbox Runtime | No | No | No | Yes | +| Deployment Workflow | No | No | No | Yes | +| Multi Runtime Backend | No | No | No | Yes | + +这张表只比较“项目自带的统一运行时平台能力”。KsADK 的设计目标不是替代这些框架,而是把它们放进同一套运行、调试、部署和观测体验里。 + +## Core Capabilities + +- `agentengine init`:创建或导入 Agent 项目。 +- `agentengine config`:管理 `.env` 和 `agentengine.yaml`。 +- `agentengine run`:本地终端运行和交互调试。 +- `agentengine web`:启动本地 Web UI,验证 streaming、附件、workspace、工具调用和会话。 +- `/v1/responses` 与 `/v1/chat/completions`:提供 OpenAI-Compatible API。 +- `ksadk.toolsets`:提供 Skill、Workspace、Platform、Sandbox 内置工具。 +- Skill Runtime:发现、下载、校验、加载并隔离执行 Skill workflow。 +- Sandbox Runtime:通过可配置后端隔离执行命令或代码。 +- Hermes & OpenClaw:面向更完整 runtime 后端的部署和更新路径。 + +## Examples + +样例仓库按场景组织,而不是只按技术框架分类: + +- [KSADK Samples](https://github.com/kingsoftcloud/ksadk-samples) +- Knowledge Assistant:知识库问答和 RAG。 +- Workflow Agent:LangGraph + AgentEngine toolsets。 +- Tool-Using Agent:自定义工具调用。 +- Memory-aware Agent:短期记忆和长期记忆接入。 + +每个公开 demo 都应包含中文 README、运行命令、环境变量说明、降级行为和验证问题。 + +## Deployment + +KsADK 支持本地优先的开发路径,也提供经过审核后可使用的部署入口: ```bash +agentengine build . agentengine launch . --target serverless +agentengine dashboard open ``` -## 包含能力 +Hermes 和 OpenClaw 更新已有实例时默认保留服务端已有 env、storage、network、memory 配置,只在显式传入对应 CLI 参数时覆盖,避免升级镜像时误改用户配置。 -- 本地开发命令:`init`、`config`、`run`、`web` -- 构建与部署命令:`build`、`deploy`、`launch` -- 远程操作:`agent invoke`、`files`、`dashboard` -- 运行时集成:ADK、LangChain、LangGraph、DeepAgents、MCP -- 托管运行时资产:Hermes 和 OpenClaw -- Skill Runtime:Skill Space 发现、zip 下载、`sha256` 校验、安全解压、instruction 加载,以及 `local_process` 或 E2B sandbox workflow 执行 -- AgentEngine 内置工具:skill 发现/加载、workspace 文件操作、component status、sandbox status 和 sandbox direct code/command execution -- Sandbox Runtime:通用沙箱抽象与 E2B 兼容后端 +## Observability -## 0.6.3 重点 +KsADK is OpenTelemetry-native. -- Hosted UI 与最新 gateway / server 对齐 `/hosted-ui/chat/`、share link、SSE 订阅和 native terminal 代理契约;`agentengine dashboard open` 继续优先打开托管入口,本地 `agentengine web` 保持调试用途。 -- LangGraph runner 在工具调用后即使没有文本流式 chunk,也会输出最终 answer,避免本地 Web UI 出现空 assistant message。 -- Skill Service 支持 `KSADK_SKILL_SERVICE_REGION=pre-online` 的 KOP 路由,自动设置预发所需 header。 -- OpenClaw / Hermes 更新已有实例时默认保留服务端已有 env、storage、network、memory 配置,只在显式传入对应 CLI 参数时覆盖。 -- `ksadk.toolsets`、Tool Gateway、Skill Runtime 与 Skill Service 相关文件纳入发布包,主推 LangGraph demo 可以在干净安装后直接绑定 AgentEngine 内置工具。 +你可以优先使用标准 OTLP 环境变量: + +```bash +OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.example.com +OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer%20token +``` + +Compatible with: -## 0.6.2 重点 +- Langfuse +- Arize +- Datadog +- Grafana +- Phoenix -- Skill Runtime 支持 Skill Space 远端发现、按需下载、`sha256` 校验、安全解压、`SKILL.md` instruction 加载,以及 `local_process` / E2B sandbox backend workflow 执行。 -- `ksadk.toolsets` 提供 Skill、Workspace、Platform、Sandbox 内置工具;推荐绑定 `get_agentengine_tools(include=["focused", "agentengine_tool_dispatcher"])`,把低频或高风险工具放进 dispatcher 按需 `list` / `describe` / `call`。 -- Tool Gateway 为 workspace 写入/删除、Skill Runtime 执行、sandbox command/code 等中高风险操作提供统一 `approval_required` envelope。 -- Workspace tools 新增 exact snippet edit 与 lightweight lint;Sandbox tools 新增 direct `run_command` / `run_code`,且只通过 configured isolated sandbox backend 执行。 -- `setup_tracing()` 优先识别标准 `OTEL_EXPORTER_OTLP_*` HTTP traces 配置,Langfuse 环境变量仍保持兼容。 -- 环境变量 registry 和公开文档覆盖 OTLP traces、AICP endpoint mode、Skill Service endpoint/scheme、Sandbox Runtime、Skill Runtime 和 Tool Gateway settings。 +Export once. Observe anywhere. -## 文档 +## 0.6.4 重点 -公开文档托管在 GitHub Pages,并使用 MkDocs Material 与双语 i18n 方案: +- 将公开定位从普通 SDK 调整为 Agent Runtime Platform,首页补齐 Why KsADK、30 秒体验、架构图、对比表、Deployment、Observability 和 Community。 +- 重构文档首页和 MkDocs 导航为 Getting Started / Build / Run / Deploy / Observe / Extend / Reference。 +- 清理 README、CHANGELOG、文档和后续 PyPI 元数据中的环境特定表述,避免公开页面出现内部环境名或内部 header。 +- 将公开定位和敏感词扫描纳入 `public-preflight`,防止后续回退。 + +## 0.6.3 重点 -- [中文文档](https://kingsoftcloud.github.io/ksadk-python/zh/) -- [English documentation](https://kingsoftcloud.github.io/ksadk-python/en/) -- [快速开始](https://kingsoftcloud.github.io/ksadk-python/getting-started/quickstart/) -- [配置项](https://kingsoftcloud.github.io/ksadk-python/getting-started/configuration/) -- [命令行参考](https://kingsoftcloud.github.io/ksadk-python/reference/cli/) -- [OpenAI 兼容 API](https://kingsoftcloud.github.io/ksadk-python/reference/openai-compatible-api/) -- [贡献指南](https://github.com/kingsoftcloud/ksadk-python/blob/main/CONTRIBUTING.md) -- [安全策略](https://github.com/kingsoftcloud/ksadk-python/blob/main/SECURITY.md) +- Hosted UI 与最新 gateway / server 契约对齐,覆盖 `/hosted-ui/chat/`、分享链接、SSE 订阅和 native terminal 代理。 +- LangGraph runner 在工具调用后即使没有文本流式 chunk,也会输出最终 answer,避免本地 Web UI 出现空 assistant message。 +- Skill Service 增强环境化路由能力,支持通过环境变量配置服务地址、region 与必要请求头映射。 +- OpenClaw / Hermes 更新已有实例时默认保留服务端已有 env、storage、network、memory 配置。 +- `ksadk.toolsets`、Tool Gateway、Skill Runtime 与 Skill Service 相关文件纳入发布包,LangGraph demo 可在干净安装后绑定 AgentEngine 内置工具。 -## 项目链接 +## Documentation - 文档: +- 中文文档: +- English documentation: +- 命令行参考: +- OpenAI-Compatible API: + +## Community + - 仓库: -- wiki: +- Wiki: - 示例仓库: - Web UI 仓库: - PyPI: - 开源协议:Apache-2.0 - -## 说明 - -- Skill 注册、CRUD 和版本治理属于 Skill Service;`ksadk` 在运行时消费 Skill Center。 -- Sandbox 模板和实例生命周期属于 Sandbox Service;`ksadk` 使用配置的沙箱后端执行运行时工作流。 -- E2B 兼容沙箱后端使用原生 `E2B_API_URL` 和 `E2B_API_KEY` 环境变量。 diff --git a/README.zh-CN.md b/README.zh-CN.md index 1ea8b03a..5720ba56 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,111 +1,188 @@ -# ksadk +# KsADK [简体中文](README.md) | [English](README.en.md) [![zread](https://img.shields.io/badge/Ask_Zread-_.svg?style=flat&color=00b0aa&labelColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTg0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTg0IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjc1ODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDQiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L3N2Zz4K&logoColor=ffffff)](https://zread.ai/kingsoftcloud/ksadk-python) -金山云 Agent Development Kit。`ksadk` 提供 Python SDK 和命令行, -安装后可使用 `agentengine` 或等价的 `ksadk` 命令创建、运行、调试、 -打包和部署 AgentEngine 智能体项目。它面向 -本地开发、Serverless 运行时、Google ADK、LangChain/LangGraph、 -DeepAgents、Hermes、OpenClaw、MCP 和 Skill Runtime 等场景。 +Build agents once. Run them anywhere. -当前版本:`0.6.3`。 +KsADK is the Agent Runtime Platform for AI agents. 你可以继续使用 Google ADK、LangGraph、LangChain 或 DeepAgents 编写业务 Agent,再用 KsADK 获得统一的本地运行、浏览器调试、OpenAI-Compatible API、沙箱执行、部署和可观测体验。 -## 安装 +当前版本:`0.6.4`。 -```bash -pip install -U ksadk -``` +- Local Development +- Browser Debugging UI +- OpenAI-Compatible API +- Unified Runtime +- Sandbox Execution +- Serverless Deployment +- Hermes & OpenClaw Runtime -按需安装可选运行时依赖: +## Why KsADK -```bash -pip install -U "ksadk[adk]" -pip install -U "ksadk[langgraph]" -pip install -U "ksadk[deepagents]" -pip install -U "ksadk[skills]" -pip install -U "ksadk[all]" -``` +Most agent frameworks solve agent development. -## 快速开始 +KsADK solves agent runtime. -以下示例使用 `agentengine`;所有命令也可以把 `agentengine` 替换为 `ksadk`。 +它不替换你的框架,而是在框架之上补齐运行时平台层: -创建并运行一个本地 Agent: +- Development:统一 `agentengine init`、`agentengine config`、`agentengine run`。 +- Debugging:本地 Web UI、会话、附件、workspace 文件和流式输出。 +- Runtime:统一 Runner、OpenAI-Compatible API 和多框架入口。 +- Sandbox:Skill Runtime、Workspace 和 sandbox backend 的隔离执行边界。 +- Deployment:Serverless、Hermes、OpenClaw 和远端 AgentEngine 入口。 +- Observability:OpenTelemetry-first tracing,可对接多种观测后端。 + +Keep using your preferred framework. Get a complete runtime platform. + +## 30 秒快速体验 ```bash -agentengine init my-agent -f langgraph -cd my-agent -agentengine config +python -m venv .venv +source .venv/bin/activate +pip install -U "ksadk[all]" + +agentengine init demo-agent -f langgraph +cd demo-agent +agentengine config set OPENAI_API_KEY=your-api-key OPENAI_MODEL_NAME=gpt-4o-mini agentengine run -i ``` -打开本地 Web UI: +打开本地浏览器调试界面: ```bash agentengine web . --no-open ``` -如需走部署形态,先使用 dry-run 或内部审核流程确认配置: +如果你的模型服务不是默认 OpenAI endpoint,再额外配置: + +```bash +agentengine config set OPENAI_BASE_URL=https://api.example.com/v1 +``` + +## Architecture + +```mermaid +flowchart TD + Code["Agent Code
ADK / LangGraph / LangChain / DeepAgents"] --> SDK["KsADK SDK
runner adapters + config"] + SDK --> Runtime["Unified Runtime
CLI + Web UI + OpenAI-Compatible API"] + Runtime --> Sandbox["Sandbox
isolated command/code execution"] + Runtime --> Skills["Skills
Skill Space + Skill Runtime"] + Runtime --> Memory["Memory & Knowledge
sessions + LTM + RAG"] + Sandbox --> Engine["AgentEngine"] + Skills --> Engine + Memory --> Engine + Engine --> Backends["Serverless / Hermes / OpenClaw Runtime"] +``` + +## Supported Frameworks + +| Framework | KsADK 负责什么 | +| --- | --- | +| Google ADK | 项目模板、Runner 适配、本地运行、Web UI 调试和部署入口。 | +| LangGraph | 图状态入口、工具调用、streaming、Skill Runtime 和 workspace toolsets。 | +| LangChain | Runnable/chain 适配、本地 OpenAI-Compatible API 和 tracing。 | +| DeepAgents | 项目入口、运行时包装、浏览器调试和部署制品。 | + +## Comparison + +| Capability | ADK | LangGraph | OpenAI Agents SDK | KsADK | +| --- | --- | --- | --- | --- | +| Agent Development | Yes | Yes | Yes | Yes | +| Browser Debugging UI | No | No | No | Yes | +| Unified CLI | No | No | No | Yes | +| OpenAI Compatible API | No | No | Partial | Yes | +| Sandbox Runtime | No | No | No | Yes | +| Deployment Workflow | No | No | No | Yes | +| Multi Runtime Backend | No | No | No | Yes | + +这张表只比较“项目自带的统一运行时平台能力”。KsADK 的设计目标不是替代这些框架,而是把它们放进同一套运行、调试、部署和观测体验里。 + +## Core Capabilities + +- `agentengine init`:创建或导入 Agent 项目。 +- `agentengine config`:管理 `.env` 和 `agentengine.yaml`。 +- `agentengine run`:本地终端运行和交互调试。 +- `agentengine web`:启动本地 Web UI,验证 streaming、附件、workspace、工具调用和会话。 +- `/v1/responses` 与 `/v1/chat/completions`:提供 OpenAI-Compatible API。 +- `ksadk.toolsets`:提供 Skill、Workspace、Platform、Sandbox 内置工具。 +- Skill Runtime:发现、下载、校验、加载并隔离执行 Skill workflow。 +- Sandbox Runtime:通过可配置后端隔离执行命令或代码。 +- Hermes & OpenClaw:面向更完整 runtime 后端的部署和更新路径。 + +## Examples + +样例仓库按场景组织,而不是只按技术框架分类: + +- [KSADK Samples](https://github.com/kingsoftcloud/ksadk-samples) +- Knowledge Assistant:知识库问答和 RAG。 +- Workflow Agent:LangGraph + AgentEngine toolsets。 +- Tool-Using Agent:自定义工具调用。 +- Memory-aware Agent:短期记忆和长期记忆接入。 + +每个公开 demo 都应包含中文 README、运行命令、环境变量说明、降级行为和验证问题。 + +## Deployment + +KsADK 支持本地优先的开发路径,也提供经过审核后可使用的部署入口: ```bash +agentengine build . agentengine launch . --target serverless +agentengine dashboard open ``` -## 包含能力 +Hermes 和 OpenClaw 更新已有实例时默认保留服务端已有 env、storage、network、memory 配置,只在显式传入对应 CLI 参数时覆盖,避免升级镜像时误改用户配置。 -- 本地开发命令:`init`、`config`、`run`、`web` -- 构建与部署命令:`build`、`deploy`、`launch` -- 远程操作:`agent invoke`、`files`、`dashboard` -- 运行时集成:ADK、LangChain、LangGraph、DeepAgents、MCP -- 托管运行时资产:Hermes 和 OpenClaw -- Skill Runtime:Skill Space 发现、zip 下载、`sha256` 校验、安全解压、instruction 加载,以及 `local_process` 或 E2B sandbox workflow 执行 -- AgentEngine 内置工具:skill 发现/加载、workspace 文件操作、component status、sandbox status 和 sandbox direct code/command execution -- Sandbox Runtime:通用沙箱抽象与 E2B 兼容后端 +## Observability -## 0.6.3 重点 +KsADK is OpenTelemetry-native. -- Hosted UI 与最新 gateway / server 对齐 `/hosted-ui/chat/`、share link、SSE 订阅和 native terminal 代理契约;`agentengine dashboard open` 继续优先打开托管入口,本地 `agentengine web` 保持调试用途。 -- LangGraph runner 在工具调用后即使没有文本流式 chunk,也会输出最终 answer,避免本地 Web UI 出现空 assistant message。 -- Skill Service 支持 `KSADK_SKILL_SERVICE_REGION=pre-online` 的 KOP 路由,自动设置预发所需 header。 -- OpenClaw / Hermes 更新已有实例时默认保留服务端已有 env、storage、network、memory 配置,只在显式传入对应 CLI 参数时覆盖。 -- `ksadk.toolsets`、Tool Gateway、Skill Runtime 与 Skill Service 相关文件纳入发布包,主推 LangGraph demo 可以在干净安装后直接绑定 AgentEngine 内置工具。 +你可以优先使用标准 OTLP 环境变量: + +```bash +OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.example.com +OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer%20token +``` + +Compatible with: -## 0.6.2 重点 +- Langfuse +- Arize +- Datadog +- Grafana +- Phoenix -- Skill Runtime 支持 Skill Space 远端发现、按需下载、`sha256` 校验、安全解压、`SKILL.md` instruction 加载,以及 `local_process` / E2B sandbox backend workflow 执行。 -- `ksadk.toolsets` 提供 Skill、Workspace、Platform、Sandbox 内置工具;推荐绑定 `get_agentengine_tools(include=["focused", "agentengine_tool_dispatcher"])`,把低频或高风险工具放进 dispatcher 按需 `list` / `describe` / `call`。 -- Tool Gateway 为 workspace 写入/删除、Skill Runtime 执行、sandbox command/code 等中高风险操作提供统一 `approval_required` envelope。 -- Workspace tools 新增 exact snippet edit 与 lightweight lint;Sandbox tools 新增 direct `run_command` / `run_code`,且只通过 configured isolated sandbox backend 执行。 -- `setup_tracing()` 优先识别标准 `OTEL_EXPORTER_OTLP_*` HTTP traces 配置,Langfuse 环境变量仍保持兼容。 -- 环境变量 registry 和公开文档覆盖 OTLP traces、AICP endpoint mode、Skill Service endpoint/scheme、Sandbox Runtime、Skill Runtime 和 Tool Gateway settings。 +Export once. Observe anywhere. -## 文档 +## 0.6.4 重点 -公开文档托管在 GitHub Pages,并使用 MkDocs Material 与双语 i18n 方案: +- 将公开定位从普通 SDK 调整为 Agent Runtime Platform,首页补齐 Why KsADK、30 秒体验、架构图、对比表、Deployment、Observability 和 Community。 +- 重构文档首页和 MkDocs 导航为 Getting Started / Build / Run / Deploy / Observe / Extend / Reference。 +- 清理 README、CHANGELOG、文档和后续 PyPI 元数据中的环境特定表述,避免公开页面出现内部环境名或内部 header。 +- 将公开定位和敏感词扫描纳入 `public-preflight`,防止后续回退。 + +## 0.6.3 重点 -- [中文文档](https://kingsoftcloud.github.io/ksadk-python/zh/) -- [English documentation](https://kingsoftcloud.github.io/ksadk-python/en/) -- [快速开始](https://kingsoftcloud.github.io/ksadk-python/getting-started/quickstart/) -- [配置项](https://kingsoftcloud.github.io/ksadk-python/getting-started/configuration/) -- [命令行参考](https://kingsoftcloud.github.io/ksadk-python/reference/cli/) -- [OpenAI 兼容 API](https://kingsoftcloud.github.io/ksadk-python/reference/openai-compatible-api/) -- [贡献指南](https://github.com/kingsoftcloud/ksadk-python/blob/main/CONTRIBUTING.md) -- [安全策略](https://github.com/kingsoftcloud/ksadk-python/blob/main/SECURITY.md) +- Hosted UI 与最新 gateway / server 契约对齐,覆盖 `/hosted-ui/chat/`、分享链接、SSE 订阅和 native terminal 代理。 +- LangGraph runner 在工具调用后即使没有文本流式 chunk,也会输出最终 answer,避免本地 Web UI 出现空 assistant message。 +- Skill Service 增强环境化路由能力,支持通过环境变量配置服务地址、region 与必要请求头映射。 +- OpenClaw / Hermes 更新已有实例时默认保留服务端已有 env、storage、network、memory 配置。 +- `ksadk.toolsets`、Tool Gateway、Skill Runtime 与 Skill Service 相关文件纳入发布包,LangGraph demo 可在干净安装后绑定 AgentEngine 内置工具。 -## 项目链接 +## Documentation - 文档: +- 中文文档: +- English documentation: +- 命令行参考: +- OpenAI-Compatible API: + +## Community + - 仓库: -- wiki: +- Wiki: - 示例仓库: - Web UI 仓库: - PyPI: - 开源协议:Apache-2.0 - -## 说明 - -- Skill 注册、CRUD 和版本治理属于 Skill Service;`ksadk` 在运行时消费 Skill Center。 -- Sandbox 模板和实例生命周期属于 Sandbox Service;`ksadk` 使用配置的沙箱后端执行运行时工作流。 -- E2B 兼容沙箱后端使用原生 `E2B_API_URL` 和 `E2B_API_KEY` 环境变量。 diff --git a/ksadk/__init__.py b/ksadk/__init__.py index c6e95436..86127bf4 100644 --- a/ksadk/__init__.py +++ b/ksadk/__init__.py @@ -1,7 +1,7 @@ """ -KsADK: Kingsoft Cloud Agent Development Kit +KsADK: Agent Runtime Platform for AI agents. -支持 LangChain / LangGraph / Google ADK 多框架的本地运行与云端部署 +统一运行、调试、部署和可观测体验,支持 ADK、LangGraph、LangChain 和 DeepAgents。 """ from ksadk.version import VERSION diff --git a/ksadk/version.py b/ksadk/version.py index 8ca36109..1ebdd1a5 100644 --- a/ksadk/version.py +++ b/ksadk/version.py @@ -1,4 +1,4 @@ """KsADK 版本信息""" -VERSION = "0.6.3" +VERSION = "0.6.4" __version__ = VERSION diff --git a/mkdocs.yml b/mkdocs.yml index 69dba887..1d697262 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,5 +1,5 @@ site_name: KsADK -site_description: 金山云智能体开发套件 +site_description: AI Agent Runtime Platform site_url: https://kingsoftcloud.github.io/ksadk-python/ repo_url: https://github.com/kingsoftcloud/ksadk-python repo_name: kingsoftcloud/ksadk-python @@ -25,43 +25,45 @@ theme: - search.share nav: - - 欢迎: index.md - - 快速开始: + - Getting Started 入门: + - 首页: index.md - 初识 KsADK: getting-started/concepts.md - 快速开始: getting-started/quickstart.md - 配置项: getting-started/configuration.md - 项目结构: getting-started/project-structure.md - - 教程: + - Build 构建: - 构建 LangGraph 智能体: tutorials/langgraph-agent.md - 构建 ADK 智能体: tutorials/adk-agent.md - 接入已有智能体: tutorials/existing-agent.md - - 指南: + - 框架接入: guides/frameworks.md + - Agent 最佳实践: guides/agent-best-practices.md + - Run 运行: - 本地 Web UI: guides/local-web-ui.md - Web UI 仓库: guides/web-ui-source.md - 运行时架构: guides/runtime-architecture.md - - 运行时产品: guides/runtime-products.md - 智能体上下文: guides/agent-context.md - - Agent 最佳实践: guides/agent-best-practices.md - - 框架接入: guides/frameworks.md - - 工具与 Skill Runtime: guides/tools-and-skill-runtime.md - - 记忆与知识库: guides/memory-knowledge.md - 附件与多模态输入: guides/attachments-multimodal.md - 工作区文件: guides/workspace-files.md - - 可观测与链路追踪: guides/observability-tracing.md + - 会话与文件: reference/runtime-sessions-files.md + - Deploy 部署: - 构建与打包: guides/build-and-package.md - - 参考: - - 命令行: reference/cli.md + - 运行时产品: guides/runtime-products.md + - 远程运行时 API: reference/remote-runtime-api.md + - 发布流程: contributing/release.md + - Observe 观测: + - 可观测与链路追踪: guides/observability-tracing.md + - 故障排查: reference/troubleshooting.md + - 测试策略: contributing/testing.md + - Extend 扩展: + - 工具与 Skill Runtime: guides/tools-and-skill-runtime.md + - 记忆与知识库: guides/memory-knowledge.md - OpenAI 兼容 API: reference/openai-compatible-api.md + - 贡献指南: contributing/index.md + - Reference 参考: + - 命令行: reference/cli.md - 项目配置: reference/project-config.md - - 远程运行时 API: reference/remote-runtime-api.md - 环境变量: reference/environment-variables.md - - 会话与文件: reference/runtime-sessions-files.md - 安全边界: reference/security-boundaries.md - - 故障排查: reference/troubleshooting.md - - 贡献: - - 贡献指南: contributing/index.md - - 测试策略: contributing/testing.md - - 发布流程: contributing/release.md exclude_docs: | internal/ @@ -81,53 +83,56 @@ plugins: build: true default: true site_name: KsADK - site_description: 金山云智能体开发套件 + site_description: AI Agent Runtime Platform theme: language: zh - locale: en name: English build: true site_name: KsADK - site_description: Kingsoft Cloud Agent Development Kit + site_description: Agent Runtime Platform for AI agents theme: language: en nav_translations: - 欢迎: Overview - 快速开始: Getting Started + Getting Started 入门: Getting Started + 首页: Overview 初识 KsADK: Concepts + 快速开始: Quick Start 配置项: Configuration 项目结构: Project Structure - 教程: Tutorials + Build 构建: Build 构建 LangGraph 智能体: Build A LangGraph Agent 构建 ADK 智能体: Build An ADK Agent 接入已有智能体: Bring An Existing Agent - 指南: Guides + Run 运行: Run 本地 Web UI: Local Web UI Web UI 仓库: Web UI Repository 运行时架构: Runtime Architecture - 运行时产品: Runtime Products 智能体上下文: Agent Context - Agent 最佳实践: Agent Best Practices - 框架接入: Frameworks - 工具与 Skill Runtime: Tools And Skill Runtime - 记忆与知识库: Memory And Knowledge 附件与多模态输入: Attachments And Multimodal Input 工作区文件: Workspace Files - 可观测与链路追踪: Observability And Tracing + 会话与文件: Runtime Sessions And Files + Deploy 部署: Deploy 构建与打包: Build And Package - 参考: Reference + 运行时产品: Runtime Products + 远程运行时 API: Remote Runtime API + 发布流程: Release Process + Observe 观测: Observe + 可观测与链路追踪: Observability And Tracing + 故障排查: Troubleshooting + 测试策略: Testing Strategy + Extend 扩展: Extend + 工具与 Skill Runtime: Tools And Skill Runtime + 记忆与知识库: Memory And Knowledge 命令行: CLI OpenAI 兼容 API: OpenAI-Compatible API + 贡献指南: Contributing Guide + Reference 参考: Reference 项目配置: Project Configuration - 远程运行时 API: Remote Runtime API 环境变量: Environment Variables - 会话与文件: Runtime Sessions And Files 安全边界: Security Boundaries - 故障排查: Troubleshooting - 贡献: Contributing - 贡献指南: Contributing Guide - 测试策略: Testing Strategy - 发布流程: Release Process + Agent 最佳实践: Agent Best Practices + 框架接入: Frameworks - mkdocstrings: handlers: python: diff --git a/public-docs/getting-started/configuration.en.md b/public-docs/getting-started/configuration.en.md index 7467b006..5c4dacaf 100644 --- a/public-docs/getting-started/configuration.en.md +++ b/public-docs/getting-started/configuration.en.md @@ -71,7 +71,7 @@ Common fields: | `framework` | framework adapter | `adk`, `langchain`, `langgraph`, `deepagents` | | `entry_point` | Python file loaded by the local runtime | `agent.py` | | `agent_variable` | exported object name | `root_agent` | -| `region` | optional cloud region for deployment-shaped commands | `cn-example-1` | +| `region` | optional cloud region for deployment-shaped commands | `cn-beijing-6` | Prefer explicit project YAML in public samples. It is easier for contributors to review than relying on framework auto-detection. diff --git a/public-docs/getting-started/configuration.md b/public-docs/getting-started/configuration.md index 90017259..e95ac489 100644 --- a/public-docs/getting-started/configuration.md +++ b/public-docs/getting-started/configuration.md @@ -63,7 +63,7 @@ agent_variable: root_agent | `framework` | 框架适配器 | `adk`、`langchain`、`langgraph`、`deepagents` | | `entry_point` | 本地运行时加载的 Python 文件 | `agent.py` | | `agent_variable` | 导出的对象名 | `root_agent` | -| `region` | 部署形态命令使用的可选云 region | `cn-example-1` | +| `region` | 部署形态命令使用的可选云 region | `cn-beijing-6` | 公开示例优先写显式项目 YAML。它比依赖自动检测更容易审核。 diff --git a/public-docs/guides/runtime-products.en.md b/public-docs/guides/runtime-products.en.md index 842568ea..e11a6ba3 100644 --- a/public-docs/guides/runtime-products.en.md +++ b/public-docs/guides/runtime-products.en.md @@ -136,7 +136,7 @@ placeholders, not real values. Do not publish: - private runtime image names or registries. -- internal pre-release endpoints. +- private-environment endpoints. - kubeconfig files or cluster names. - real channel tokens, model keys, or kdocs tokens. - customer workspace paths or object storage buckets. @@ -144,4 +144,3 @@ Do not publish: The public docs should explain the contract and lifecycle. Operational details for a specific private environment belong in internal documentation. - diff --git a/public-docs/guides/runtime-products.md b/public-docs/guides/runtime-products.md index 96250259..c0f9f567 100644 --- a/public-docs/guides/runtime-products.md +++ b/public-docs/guides/runtime-products.md @@ -131,11 +131,10 @@ Hermes 和 OpenClaw 可能从环境变量读取模型、记忆、channel 或工 不要发布: - 私有 runtime 镜像名或 registry。 -- 内部预发 endpoint。 +- 私有环境 endpoint。 - kubeconfig 文件或集群名称。 - 真实 channel token、模型 key 或 kdocs token。 - 客户 workspace 路径或对象存储 bucket。 - 绑定内部平台的事故 runbook。 公开文档解释 contract 和生命周期。具体私有环境的运维细节留在内部文档。 - diff --git a/public-docs/index.en.md b/public-docs/index.en.md index 48096c50..fd35ddb5 100644 --- a/public-docs/index.en.md +++ b/public-docs/index.en.md @@ -1,180 +1,178 @@ # KsADK -Kingsoft Cloud Agent Development Kit for building, running, debugging, and -packaging Python agent applications. KsADK gives developers one local CLI, -runtime surface, OpenAI-compatible protocol layer, and browser UI across Google -ADK, LangGraph, LangChain, and DeepAgents projects. +Build agents once. Run them anywhere. -=== "Python" +KsADK is the Agent Runtime Platform for AI agents. + +Build with Google ADK, LangGraph, LangChain, or DeepAgents. Run, debug, expose, observe, and deploy those agents through one unified runtime experience. + +=== "Install" ```bash - pip install -U ksadk - pip install -U "ksadk[langgraph]" + pip install -U "ksadk[all]" ``` === "Create" ```bash - agentengine init my-agent -f langgraph - cd my-agent - agentengine config set OPENAI_API_KEY=sk-test OPENAI_BASE_URL=https://api.example.com/v1 OPENAI_MODEL_NAME=my-model + agentengine init demo-agent -f langgraph + cd demo-agent + agentengine config set OPENAI_API_KEY=your-api-key OPENAI_MODEL_NAME=gpt-4o-mini ``` === "Run" ```bash - agentengine run . -i + agentengine run -i agentengine web . --no-open ``` -This site is the curated public documentation for the open-source SDK. It is -separate from generated `.zread/` code-reading output, internal deployment -notes, and private AgentEngine operating procedures. +## Why KsADK -## System At A Glance +Most agent frameworks solve agent development. -```mermaid -flowchart LR - Dev["Developer"] --> CLI["agentengine CLI"] - CLI --> Detect["project detection
agentengine.yaml / ksadk.yaml / conventions"] - Detect --> Runner["framework runner
ADK / LangGraph / LangChain / DeepAgents"] - Runner --> Runtime["local runtime"] - Runtime --> API["OpenAI-compatible APIs
/v1/responses
/v1/chat/completions"] - Runtime --> UI["local Web UI
agentengine web"] - Runtime --> Sessions["sessions, attachments,
workspace files, tracing"] - CLI --> Package["build / launch
reviewed cloud path"] - UI -. "editable source" .-> Web["kingsoftcloud/ksadk-web"] -``` +KsADK solves agent runtime. -The important design choice is that the SDK does not replace the framework -where the agent is written. It detects and loads the project, adapts it through -a runner, then exposes the same local development experience to terminal users, -browser users, and API clients. +KsADK does not replace your agent framework. It provides a unified platform layer for development, debugging, runtime, sandbox, deployment, and observability: -## Documentation Style +- Development: one CLI for project creation, configuration, and local runs. +- Debugging: browser UI, sessions, attachments, workspace files, and streaming. +- Runtime: framework runners, OpenAI-Compatible APIs, and consistent invocation. +- Sandbox: Skill Runtime, Workspace, and isolated sandbox backend boundaries. +- Deployment: Serverless, Hermes, OpenClaw, and remote AgentEngine entrypoints. +- Observability: OpenTelemetry-first tracing for multiple backends. -KsADK follows the public-docs pattern used by mature agent SDK projects: +## 30 Seconds Quick Start -- a short overview for positioning. -- a quickstart that reaches a running local agent. -- tutorials with complete files. -- guides for common tasks and operational decisions. -- references for command, config, and API contracts. -- contribution, release, security, and publication gates. +```bash +python -m venv .venv +source .venv/bin/activate +pip install -U "ksadk[all]" -Generated code-reading output can help maintainers understand the repository, -but it is not the public documentation source. Public docs must be reviewed, -stable, linkable, and safe to publish on GitHub Pages. +agentengine init demo-agent -f langgraph +cd demo-agent +agentengine config set OPENAI_API_KEY=your-api-key OPENAI_MODEL_NAME=gpt-4o-mini +agentengine run -i +``` -## Developer Journey +Open the local Web UI: + +```bash +agentengine web . --no-open +``` + +If your model provider is not the default OpenAI endpoint, also set: + +```bash +agentengine config set OPENAI_BASE_URL=https://api.example.com/v1 +``` + +## Architecture ```mermaid flowchart TD - A["Install ksadk"] --> B["Create or import an agent project"] - B --> C["Set model/provider configuration"] - C --> D["Run in terminal"] - D --> E["Debug in local Web UI"] - E --> F["Call local OpenAI-compatible APIs"] - F --> G["Add tools, files, memory, tracing"] - G --> H["Build and review release artifacts"] - H --> I["Publish only after maintainer approval"] + Code["Agent Code
ADK / LangGraph / LangChain / DeepAgents"] --> SDK["KsADK SDK
runner adapters + config"] + SDK --> Runtime["Unified Runtime
CLI + Web UI + OpenAI-Compatible API"] + Runtime --> Sandbox["Sandbox
isolated command/code execution"] + Runtime --> Skills["Skills
Skill Space + Skill Runtime"] + Runtime --> Memory["Memory & Knowledge
sessions + LTM + RAG"] + Sandbox --> Engine["AgentEngine"] + Skills --> Engine + Memory --> Engine + Engine --> Backends["Serverless / Hermes / OpenClaw Runtime"] ``` -## What KsADK Provides +## Supported Frameworks -| Area | What you get | +| Framework | What KsADK adds | | --- | --- | -| Project bootstrap | `agentengine init` templates for supported framework families. | -| Local runtime | `agentengine run` starts a local API server for an agent project. | -| Local Web UI | `agentengine web` opens a browser-based invoke/debug interface. | -| Configuration | `agentengine config` manages project `.env` and YAML settings. | -| Packaging | `agentengine build` prepares deployment artifacts when cloud credentials are configured. | -| Protocols | Local OpenAI-compatible `/v1/responses` and `/v1/chat/completions` endpoints. | -| Extensibility | Framework adapters, memory hooks, MCP/A2A integration points, and release tooling. | +| Google ADK | Templates, runner adapter, local runtime, Web UI debugging, and deployment entrypoints. | +| LangGraph | Graph-state entrypoint, tool calling, streaming, Skill Runtime, and workspace toolsets. | +| LangChain | Runnable/chain adaptation, local OpenAI-Compatible APIs, and tracing. | +| DeepAgents | Project entrypoint, runtime wrapping, browser debugging, and deployment artifacts. | -## Typical Use Cases +## Comparison -Use KsADK when you need to: +| Capability | ADK | LangGraph | OpenAI Agents SDK | KsADK | +| --- | --- | --- | --- | --- | +| Agent Development | Yes | Yes | Yes | Yes | +| Browser Debugging UI | No | No | No | Yes | +| Unified CLI | No | No | No | Yes | +| OpenAI Compatible API | No | No | Partial | Yes | +| Sandbox Runtime | No | No | No | Yes | +| Deployment Workflow | No | No | No | Yes | +| Multi Runtime Backend | No | No | No | Yes | -- run the same local command against ADK, LangGraph, LangChain, or DeepAgents - projects. -- expose a local OpenAI-compatible endpoint for an agent project. -- debug an agent in a browser without setting up hosted infrastructure. -- prepare an agent package for a reviewed cloud deployment path. -- keep Python SDK docs, Web UI docs, and release checks aligned before a public - GitHub import. +This table compares unified runtime-platform capabilities provided by the project itself. KsADK complements agent frameworks instead of replacing them. -## Open-Source Boundary +## Core Capabilities -The public repository contains the SDK, CLI, runtime adapters, local development -experience, curated documentation, and release checks. +| Capability | Common entrypoints | +| --- | --- | +| Local Development | `agentengine init`, `agentengine config`, `agentengine run` | +| Browser Debugging UI | `agentengine web` | +| OpenAI-Compatible API | `/v1/responses`, `/v1/chat/completions` | +| Unified Runtime | ADK / LangGraph / LangChain / DeepAgents runners | +| Sandbox Execution | Skill Runtime, Workspace tools, Sandbox tools | +| Serverless Deployment | `agentengine build`, `agentengine launch` | +| Hermes & OpenClaw Runtime | `agentengine hermes ...`, `agentengine openclaw ...` | -It does not publish the full AgentEngine control plane, internal Kubernetes -deployment automation, internal kubeconfig material, private registries, customer -data, or private support runbooks. Cloud deployment commands are documented as -SDK entry points, but public examples must be runnable locally without internal -accounts. +## Examples -## First Workflow +The public samples repository is organized by scenario, not only by framework: -```bash -python -m venv .venv -source .venv/bin/activate -pip install -U ksadk +- [KSADK Samples](https://github.com/kingsoftcloud/ksadk-samples) +- Knowledge Assistant: RAG and knowledge-base QA. +- Workflow Agent: LangGraph plus AgentEngine toolsets. +- Tool-Using Agent: custom business tools. +- Memory-aware Agent: short-term and long-term memory patterns. -agentengine init my-agent -f langgraph -cd my-agent -agentengine config set OPENAI_API_KEY=sk-test OPENAI_BASE_URL=https://api.example.com/v1 OPENAI_MODEL_NAME=my-model -agentengine run -i -``` +## Deployment -Then open the local Web UI: +KsADK is local-first, with reviewed deployment entrypoints when you are ready: ```bash -agentengine web . --no-open +agentengine build . +agentengine launch . --target serverless +agentengine dashboard open ``` -If you already have an agent file, use: +When updating existing Hermes or OpenClaw instances, KsADK preserves server-side env, storage, network, and memory configuration by default. Those groups are overwritten only when matching CLI options are provided explicitly. + +## Observability + +KsADK is OpenTelemetry-native. ```bash -agentengine init my-agent --from-agent ./agent.py -cd my-agent -agentengine run . -i +OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.example.com +OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer%20token ``` -## Documentation Map - -- [Concepts](getting-started/concepts.en.md): how the SDK, project config, runtime, and Web UI fit together. -- [Quickstart](getting-started/quickstart.en.md): create, configure, run, and debug a local agent. -- [Configuration](getting-started/configuration.en.md): environment variables and project YAML. -- [Project Structure](getting-started/project-structure.en.md): files created by templates and files to avoid committing. -- [Build A LangGraph Agent](tutorials/langgraph-agent.en.md): complete local project with source code. -- [Bring An Existing Agent](tutorials/existing-agent.en.md): wrap an existing file or package. -- [Local Web UI](guides/local-web-ui.en.md): local browser debugging and the independent `ksadk-web` repository plan. -- [Web UI Repository](guides/web-ui-source.en.md): how `ksadk-web`, hosted UI, and the Python wheel relate. -- [Runtime Products](guides/runtime-products.en.md): Hermes and OpenClaw lifecycle, runtime surfaces, and public-safe boundaries. -- [Frameworks](guides/frameworks.en.md): ADK, LangGraph, LangChain, and DeepAgents conventions. -- [Agent Best Practices](guides/agent-best-practices.en.md): LangGraph/ADK patterns with knowledge, memory, sessions, Skill Runtime, MCP, and workspace files. -- [Tools And Skill Runtime](guides/tools-and-skill-runtime.en.md): built-in toolsets, focused/dispatcher progressive disclosure, Tool Gateway, MCP/A2A, and Skill Runtime boundaries. -- [Observability And Tracing](guides/observability-tracing.en.md): local spans, Langfuse, OTLP, and trace metadata rules. -- [Build And Package](guides/build-and-package.en.md): local builds, review gates, and public artifact rules. -- [CLI Reference](reference/cli.en.md): public command surface and common options. -- [OpenAI-Compatible API](reference/openai-compatible-api.en.md): local protocol shape and KsADK extensions. -- [Project Configuration](reference/project-config.en.md): YAML and environment field reference. -- [Remote Runtime API](reference/remote-runtime-api.en.md): PublicEndpoint, authentication, OpenAI-compatible routes, workspace files, Hermes, and OpenClaw. -- [Environment Variables](reference/environment-variables.en.md): model, session, memory, knowledge, Skill Runtime, MCP, build, and tracing variables. -- [Runtime Sessions And Files](reference/runtime-sessions-files.en.md): session IDs, uploads, workspace previews, and local state. -- [Security Boundaries](reference/security-boundaries.en.md): public repository, workspace, preview, package, and history boundaries. -- [Troubleshooting](reference/troubleshooting.en.md): common setup, runtime, and packaging failures. - -## Publication State - -The planned public locations are: - -- Python SDK repository: `https://github.com/kingsoftcloud/ksadk-python` -- Python SDK docs: `https://kingsoftcloud.github.io/ksadk-python/` -- Web UI repository: `https://github.com/kingsoftcloud/ksadk-web` -- Web UI docs or demo: `https://kingsoftcloud.github.io/ksadk-web/` - -The first real source import must be reviewed internally before GitHub source, -GitHub Pages, GitHub releases, or PyPI publication are enabled. +Compatible with: + +- Langfuse +- Arize +- Datadog +- Grafana +- Phoenix + +Export once. Observe anywhere. + +## Documentation + +- [Getting Started](getting-started/quickstart.en.md) +- [Build](tutorials/langgraph-agent.en.md) +- [Run](guides/local-web-ui.en.md) +- [Deploy](guides/build-and-package.en.md) +- [Observe](guides/observability-tracing.en.md) +- [Extend](guides/tools-and-skill-runtime.en.md) +- [Reference](reference/cli.en.md) + +## Community + +- Repository: +- Wiki: +- Samples repository: +- Web UI repository: +- PyPI: +- License: Apache-2.0 diff --git a/public-docs/index.md b/public-docs/index.md index 46b034af..30e6584a 100644 --- a/public-docs/index.md +++ b/public-docs/index.md @@ -1,171 +1,178 @@ # KsADK -金山云智能体开发套件,用于创建、运行、调试和打包 Python Agent 应用。 -KsADK 在 Google ADK、LangGraph、LangChain 和 DeepAgents 项目之上提供 -统一的本地 CLI、运行时、OpenAI 兼容协议层和浏览器调试界面。 +Build agents once. Run them anywhere. -=== "Python" +KsADK is the Agent Runtime Platform for AI agents. + +你可以继续使用 Google ADK、LangGraph、LangChain 或 DeepAgents 编写业务 Agent,再用 KsADK 获得统一的本地运行、浏览器调试、OpenAI-Compatible API、沙箱执行、部署和可观测体验。 + +=== "安装" ```bash - pip install -U ksadk - pip install -U "ksadk[langgraph]" + pip install -U "ksadk[all]" ``` -=== "创建项目" +=== "创建" ```bash - agentengine init my-agent -f langgraph - cd my-agent - agentengine config set OPENAI_API_KEY=sk-test OPENAI_BASE_URL=https://api.example.com/v1 OPENAI_MODEL_NAME=my-model + agentengine init demo-agent -f langgraph + cd demo-agent + agentengine config set OPENAI_API_KEY=your-api-key OPENAI_MODEL_NAME=gpt-4o-mini ``` -=== "本地运行" +=== "运行" ```bash - agentengine run . -i + agentengine run -i agentengine web . --no-open ``` -本站是开源 SDK 的人工整理公开文档。它不发布 `.zread/` 代码阅读结果、 -内部部署说明或私有 AgentEngine 运维流程。 +## Why KsADK -## 架构一览 +Most agent frameworks solve agent development. -```mermaid -flowchart LR - Dev["开发者"] --> CLI["agentengine CLI"] - CLI --> Detect["项目检测
agentengine.yaml / ksadk.yaml / 约定"] - Detect --> Runner["框架 Runner
ADK / LangGraph / LangChain / DeepAgents"] - Runner --> Runtime["本地运行时"] - Runtime --> API["OpenAI 兼容 API
/v1/responses
/v1/chat/completions"] - Runtime --> UI["本地 Web UI
agentengine web"] - Runtime --> Sessions["会话、附件、
工作区文件、Tracing"] - CLI --> Package["build / launch
审核后的云端路径"] - UI -. "可编辑源代码" .-> Web["kingsoftcloud/ksadk-web"] -``` +KsADK solves agent runtime. -这个设计的核心是:KsADK 不替换你写 Agent 时使用的框架。它负责发现项目、 -加载入口、适配 Runner,并把同一套本地开发体验提供给终端、浏览器和 API -客户端。 +KsADK 不替换你已经选择的 Agent 框架。它在框架之上提供统一平台层,把开发、调试、运行、沙箱、部署和可观测连接起来: -## 文档定位 +- Development:统一项目创建、配置和本地运行。 +- Debugging:浏览器调试 UI、会话、附件、workspace 文件和 streaming。 +- Runtime:统一 Runner、OpenAI-Compatible API 和多框架入口。 +- Sandbox:Skill Runtime、Workspace 和 sandbox backend 的隔离执行边界。 +- Deployment:Serverless、Hermes、OpenClaw 和远端 AgentEngine 入口。 +- Observability:OpenTelemetry-first tracing,可接入多种观测后端。 -KsADK 参考成熟 Agent SDK 项目的公开文档组织方式: +## 30 秒快速体验 -- 概览页说明定位和主要入口。 -- 快速开始把用户带到一个可以运行的本地 Agent。 -- 教程给出完整文件。 -- 指南解释常见任务和取舍。 -- 参考页定义命令、配置和 API 契约。 -- 贡献、发布、安全和公开审计规则作为治理文档。 +```bash +python -m venv .venv +source .venv/bin/activate +pip install -U "ksadk[all]" -zread 生成的代码阅读结果可以帮助维护者理解仓库,但不是公开文档源。公开文档 -必须经过人工整理、可链接、可审核,并且可以安全发布到 GitHub Pages。 +agentengine init demo-agent -f langgraph +cd demo-agent +agentengine config set OPENAI_API_KEY=your-api-key OPENAI_MODEL_NAME=gpt-4o-mini +agentengine run -i +``` -## 开发路径 +启动本地 Web UI: + +```bash +agentengine web . --no-open +``` + +如果使用非默认 OpenAI endpoint,再额外设置: + +```bash +agentengine config set OPENAI_BASE_URL=https://api.example.com/v1 +``` + +## Architecture ```mermaid flowchart TD - A["安装 ksadk"] --> B["创建或导入 Agent 项目"] - B --> C["配置模型与 provider"] - C --> D["终端交互运行"] - D --> E["本地 Web UI 调试"] - E --> F["调用本地 OpenAI 兼容 API"] - F --> G["添加工具、文件、记忆和追踪"] - G --> H["构建并审核发布制品"] - H --> I["维护者批准后再公开发布"] + Code["Agent Code
ADK / LangGraph / LangChain / DeepAgents"] --> SDK["KsADK SDK
runner adapters + config"] + SDK --> Runtime["Unified Runtime
CLI + Web UI + OpenAI-Compatible API"] + Runtime --> Sandbox["Sandbox
isolated command/code execution"] + Runtime --> Skills["Skills
Skill Space + Skill Runtime"] + Runtime --> Memory["Memory & Knowledge
sessions + LTM + RAG"] + Sandbox --> Engine["AgentEngine"] + Skills --> Engine + Memory --> Engine + Engine --> Backends["Serverless / Hermes / OpenClaw Runtime"] ``` -## KsADK 提供什么 +## Supported Frameworks -| 能力区域 | 你会得到什么 | +| Framework | KsADK 负责什么 | | --- | --- | -| 项目脚手架 | 面向不同框架族的 `agentengine init` 模板。 | -| 本地运行时 | `agentengine run` 为 Agent 项目启动本地 API 服务。 | -| 本地 Web UI | `agentengine web` 打开浏览器调用和调试界面。 | -| 配置管理 | `agentengine config` 管理项目 `.env` 与 YAML 设置。 | -| 打包 | 在配置云凭证后,`agentengine build` 准备部署制品。 | -| 协议 | 本地 OpenAI 兼容 `/v1/responses` 与 `/v1/chat/completions`。 | -| 扩展能力 | 框架适配、记忆 hook、MCP/A2A 接入点和发布工具链。 | +| Google ADK | 项目模板、Runner 适配、本地运行、Web UI 调试和部署入口。 | +| LangGraph | 图状态入口、工具调用、streaming、Skill Runtime 和 workspace toolsets。 | +| LangChain | Runnable/chain 适配、本地 OpenAI-Compatible API 和 tracing。 | +| DeepAgents | 项目入口、运行时包装、浏览器调试和部署制品。 | -## 典型场景 +## Comparison -适合使用 KsADK 的情况: +| Capability | ADK | LangGraph | OpenAI Agents SDK | KsADK | +| --- | --- | --- | --- | --- | +| Agent Development | Yes | Yes | Yes | Yes | +| Browser Debugging UI | No | No | No | Yes | +| Unified CLI | No | No | No | Yes | +| OpenAI Compatible API | No | No | Partial | Yes | +| Sandbox Runtime | No | No | No | Yes | +| Deployment Workflow | No | No | No | Yes | +| Multi Runtime Backend | No | No | No | Yes | -- 希望用同一组本地命令运行 ADK、LangGraph、LangChain 或 DeepAgents 项目。 -- 希望为 Agent 项目暴露本地 OpenAI 兼容 endpoint。 -- 希望不搭建 hosted 基础设施就能在浏览器里调试 Agent。 -- 希望为经过审核的云端部署路径准备 Agent 包。 -- 希望 Python SDK 文档、Web UI 文档和发布检查在公开 GitHub 导入前保持一致。 +这张表只比较项目自带的统一运行时平台能力。KsADK 的设计目标不是替代这些框架,而是把它们放进同一套运行、调试、部署和观测体验里。 -## 开源边界 +## Core Capabilities -公开仓库包含 SDK、CLI、运行时适配、本地开发体验、人工整理文档和发布检查。 +| 能力 | 最常用入口 | +| --- | --- | +| Local Development | `agentengine init`、`agentengine config`、`agentengine run` | +| Browser Debugging UI | `agentengine web` | +| OpenAI-Compatible API | `/v1/responses`、`/v1/chat/completions` | +| Unified Runtime | ADK / LangGraph / LangChain / DeepAgents Runner | +| Sandbox Execution | Skill Runtime、Workspace tools、Sandbox tools | +| Serverless Deployment | `agentengine build`、`agentengine launch` | +| Hermes & OpenClaw Runtime | `agentengine hermes ...`、`agentengine openclaw ...` | -公开仓库不发布完整 AgentEngine 控制面、内部 Kubernetes 部署自动化、内部 -kubeconfig、私有 registry、客户数据或内部支持 runbook。云端部署命令会作为 SDK -入口记录,但公开示例必须能在没有内部账号的情况下本地运行。 +## Examples -## 第一个工作流 +公开样例仓库按场景组织,而不是只按技术框架分类: -```bash -python -m venv .venv -source .venv/bin/activate -pip install -U ksadk +- [KSADK Samples](https://github.com/kingsoftcloud/ksadk-samples) +- Knowledge Assistant:知识库问答和 RAG。 +- Workflow Agent:LangGraph + AgentEngine toolsets。 +- Tool-Using Agent:自定义工具调用。 +- Memory-aware Agent:短期记忆和长期记忆接入。 -agentengine init my-agent -f langgraph -cd my-agent -agentengine config set OPENAI_API_KEY=sk-test OPENAI_BASE_URL=https://api.example.com/v1 OPENAI_MODEL_NAME=my-model -agentengine run -i -``` +## Deployment -然后启动本地 Web UI: +KsADK 支持本地优先开发,也提供经过审核后可使用的部署入口: ```bash -agentengine web . --no-open +agentengine build . +agentengine launch . --target serverless +agentengine dashboard open ``` -如果已经有一个 Agent 文件,可以导入: +Hermes 和 OpenClaw 更新已有实例时默认保留服务端已有 env、storage、network、memory 配置,只在显式传入对应 CLI 参数时覆盖,避免升级镜像时误改用户配置。 + +## Observability + +KsADK is OpenTelemetry-native. ```bash -agentengine init my-agent --from-agent ./agent.py -cd my-agent -agentengine run . -i +OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.example.com +OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer%20token ``` -## 文档地图 - -- [初识 KsADK](getting-started/concepts.md):SDK、项目配置、运行时和 Web UI 如何协作。 -- [快速开始](getting-started/quickstart.md):创建、配置、运行和调试本地 Agent。 -- [配置项](getting-started/configuration.md):环境变量和项目 YAML。 -- [项目结构](getting-started/project-structure.md):模板创建的文件以及不应提交的文件。 -- [构建 LangGraph 智能体](tutorials/langgraph-agent.md):包含完整源码的本地项目。 -- [接入已有智能体](tutorials/existing-agent.md):包装已有文件或包。 -- [本地 Web UI](guides/local-web-ui.md):本地浏览器调试和独立 `ksadk-web` 仓库计划。 -- [Web UI 仓库](guides/web-ui-source.md):`ksadk-web`、hosted UI 和 Python wheel 的关系。 -- [运行时产品](guides/runtime-products.md):Hermes 和 OpenClaw 的生命周期、runtime surface 和公开安全边界。 -- [框架接入](guides/frameworks.md):ADK、LangGraph、LangChain 和 DeepAgents 约定。 -- [Agent 最佳实践](guides/agent-best-practices.md):LangGraph/ADK 模式,以及知识库、记忆库、会话、Skill Runtime、MCP 和 workspace 文件。 -- [工具与 Skill Runtime](guides/tools-and-skill-runtime.md):内置 toolsets、focused/dispatcher 渐进式披露、Tool Gateway、MCP/A2A 和 Skill Runtime 边界。 -- [可观测与链路追踪](guides/observability-tracing.md):本地 spans、Langfuse、OTLP 和 trace metadata 规则。 -- [构建与打包](guides/build-and-package.md):本地构建、审核 gate 和公开 artifact 规则。 -- [命令行参考](reference/cli.md):公开命令面和常见选项。 -- [OpenAI 兼容 API](reference/openai-compatible-api.md):本地协议形态和 KsADK 扩展。 -- [项目配置](reference/project-config.md):YAML 和环境字段参考。 -- [远程运行时 API](reference/remote-runtime-api.md):PublicEndpoint、鉴权、OpenAI 兼容路由、workspace files、Hermes 和 OpenClaw。 -- [环境变量](reference/environment-variables.md):模型、会话、记忆、知识库、Skill Runtime、MCP、构建和 tracing 变量。 -- [会话与文件](reference/runtime-sessions-files.md):session id、上传、工作区预览和本地状态。 -- [安全边界](reference/security-boundaries.md):公开仓库、工作区、预览、包和历史记录边界。 -- [故障排查](reference/troubleshooting.md):常见安装、运行时和打包问题。 - -## 发布状态 - -计划公开位置: - -- Python SDK 仓库:`https://github.com/kingsoftcloud/ksadk-python` -- Python SDK 文档:`https://kingsoftcloud.github.io/ksadk-python/` -- Web UI 仓库:`https://github.com/kingsoftcloud/ksadk-web` -- Web UI 文档或演示:`https://kingsoftcloud.github.io/ksadk-web/` - -第一次真实源码导入必须先完成内部审核,然后才能启用 GitHub source、 -GitHub Pages、GitHub Releases 或 PyPI 发布。 +Compatible with: + +- Langfuse +- Arize +- Datadog +- Grafana +- Phoenix + +Export once. Observe anywhere. + +## Documentation + +- [Getting Started 入门](getting-started/quickstart.md) +- [Build 构建](tutorials/langgraph-agent.md) +- [Run 运行](guides/local-web-ui.md) +- [Deploy 部署](guides/build-and-package.md) +- [Observe 观测](guides/observability-tracing.md) +- [Extend 扩展](guides/tools-and-skill-runtime.md) +- [Reference 参考](reference/cli.md) + +## Community + +- 仓库: +- Wiki: +- 示例仓库: +- Web UI 仓库: +- PyPI: +- 开源协议:Apache-2.0 diff --git a/pyproject.toml b/pyproject.toml index 3778bda0..af07f019 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta" [project] name = "ksadk" -version = "0.6.3" -description = "Kingsoft Cloud Agent Development Kit - 支持 LangChain/LangGraph/DeepAgents/ADK/OpenClaw/Hermes 的本地运行与云端部署" +version = "0.6.4" +description = "KsADK Agent Runtime Platform - unified runtime, debugging, deployment and observability for AI agents" readme = "README.md" requires-python = ">=3.10" license = "Apache-2.0" diff --git a/tests/test_public_positioning_docs.py b/tests/test_public_positioning_docs.py new file mode 100644 index 00000000..074d7819 --- /dev/null +++ b/tests/test_public_positioning_docs.py @@ -0,0 +1,172 @@ +from __future__ import annotations + +from pathlib import Path +import tomllib +import yaml + + +ROOT = Path(__file__).resolve().parents[1] + + +class MkdocsTestLoader(yaml.SafeLoader): + pass + + +def _ignore_python_name(loader: MkdocsTestLoader, node: yaml.Node): + return loader.construct_scalar(node) + + +MkdocsTestLoader.add_constructor( + "tag:yaml.org,2002:python/name:pymdownx.superfences.fence_code_format", + _ignore_python_name, +) + + +def _read(relative_path: str) -> str: + return (ROOT / relative_path).read_text(encoding="utf-8") + + +def _public_markdown_and_config_files() -> list[Path]: + files = [ + ROOT / "README.md", + ROOT / "README.zh-CN.md", + ROOT / "README.en.md", + ROOT / "CHANGELOG.md", + ROOT / "mkdocs.yml", + ROOT / "pyproject.toml", + ] + files.extend(sorted((ROOT / "public-docs").rglob("*.md"))) + return files + + +def test_readmes_position_ksadk_as_runtime_platform(): + expected_sections = ( + "Build agents once. Run them anywhere.", + "Agent Runtime Platform", + "Why KsADK", + "30 秒快速体验", + "Architecture", + "Comparison", + "Observability", + "Deployment", + "Community", + ) + for relative_path in ("README.md", "README.zh-CN.md"): + text = _read(relative_path) + for expected in expected_sections: + assert expected in text, f"{relative_path} missing {expected}" + assert "Agent Development Kit" not in text + assert "KSADK_SKILL_SERVICE_REGION=pre-online" not in text + + +def test_english_readme_positions_ksadk_as_runtime_platform(): + text = _read("README.en.md") + expected_sections = ( + "Build agents once. Run them anywhere.", + "Agent Runtime Platform", + "Why KsADK", + "30 Seconds Quick Start", + "Architecture", + "Comparison", + "Observability", + "Deployment", + "Community", + ) + for expected in expected_sections: + assert expected in text + assert "Agent Development Kit" not in text + assert "KSADK_SKILL_SERVICE_REGION=pre-online" not in text + + +def test_docs_homepage_uses_runtime_platform_information_architecture(): + zh = _read("public-docs/index.md") + en = _read("public-docs/index.en.md") + for text in (zh, en): + for expected in ( + "Build agents once. Run them anywhere.", + "Agent Runtime Platform", + "Why KsADK", + "Comparison", + "OpenTelemetry", + "Hermes", + "OpenClaw", + ): + assert expected in text + assert "Agent Development Kit" not in text + assert "成熟 Agent SDK" not in text + + +def test_public_navigation_is_task_oriented(): + mkdocs = _read("mkdocs.yml") + for expected in ("Getting Started", "Build", "Run", "Deploy", "Observe", "Extend", "Reference"): + assert expected in mkdocs + assert "快速开始: Quick Start" in mkdocs + assert "Kingsoft Cloud Agent Development Kit" not in mkdocs + assert "金山云智能体开发套件" not in mkdocs + + +def test_english_navigation_translates_all_chinese_labels(): + config = yaml.load(_read("mkdocs.yml"), Loader=MkdocsTestLoader) + translations = ( + config["plugins"][1]["i18n"]["languages"][1]["nav_translations"] + ) + + def iter_labels(items): + for item in items: + if isinstance(item, str): + yield Path(item).stem + elif isinstance(item, dict): + for label, children in item.items(): + yield str(label) + if isinstance(children, list): + yield from iter_labels(children) + + missing = sorted( + label + for label in iter_labels(config["nav"]) + if any("\u4e00" <= character <= "\u9fff" for character in label) + and label not in translations + ) + + assert missing == [] + + +def test_public_materials_do_not_publish_environment_specific_release_words(): + forbidden = ( + "pre-online", + "内部预发 endpoint", + "internal pre-release endpoints", + "X-Ksc-Region", + "X-KSC-CUSTOM-SOURCE", + "agent-api-pre", + "kspmas-internal", + "aicp.inner.api", + "maicp.inner", + ) + for path in _public_markdown_and_config_files(): + text = path.read_text(encoding="utf-8") + relative_path = path.relative_to(ROOT) + for fragment in forbidden: + assert fragment not in text, f"{relative_path} contains {fragment}" + + +def test_package_metadata_is_runtime_platform_positioned_for_patch_candidate(): + pyproject = tomllib.loads(_read("pyproject.toml")) + init_text = _read("ksadk/__init__.py") + version_text = _read("ksadk/version.py") + + assert pyproject["project"]["version"] == "0.6.4" + assert 'VERSION = "0.6.4"' in version_text + assert "Agent Runtime Platform" in pyproject["project"]["description"] + assert "Agent Runtime Platform" in init_text + assert "Agent Development Kit" not in pyproject["project"]["description"] + assert "Agent Development Kit" not in init_text + + +def test_patch_version_changelog_is_unreleased_until_user_review(): + changelog = _read("CHANGELOG.md") + assert "## [0.6.4] - Unreleased" in changelog + assert "用户 review 通过前" in changelog + assert "不创建 tag" in changelog + assert "不发布 GitHub Release" in changelog + assert "不上传 PyPI" in changelog diff --git a/uv.lock b/uv.lock index 9d458ec7..be2e353d 100644 --- a/uv.lock +++ b/uv.lock @@ -2451,7 +2451,7 @@ wheels = [ [[package]] name = "ksadk" -version = "0.6.3" +version = "0.6.4" source = { editable = "." } dependencies = [ { name = "a2a-sdk" }, From 0234b967f2e56edd268590e50dde8aef4676653e Mon Sep 17 00:00:00 2001 From: xiayu Date: Wed, 10 Jun 2026 07:22:11 +0800 Subject: [PATCH 02/20] docs: document default public cloud region --- README.en.md | 6 ++++++ README.md | 6 ++++++ README.zh-CN.md | 6 ++++++ public-docs/index.en.md | 6 ++++++ public-docs/index.md | 6 ++++++ tests/test_public_positioning_docs.py | 3 +++ 6 files changed, 33 insertions(+) diff --git a/README.en.md b/README.en.md index 9cf10d2a..d304a402 100644 --- a/README.en.md +++ b/README.en.md @@ -60,6 +60,12 @@ If your model provider is not the default OpenAI endpoint, also set: agentengine config set OPENAI_BASE_URL=https://api.example.com/v1 ``` +If you need Kingsoft Cloud AgentEngine, Skill Service, knowledge base, or long-term memory services, set the default public cloud region explicitly: + +```bash +agentengine config set KSYUN_REGION=cn-beijing-6 +``` + ## Architecture ```mermaid diff --git a/README.md b/README.md index 5720ba56..ff768ef0 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,12 @@ agentengine web . --no-open agentengine config set OPENAI_BASE_URL=https://api.example.com/v1 ``` +如果需要调用金山云 AgentEngine、Skill Service、知识库或长期记忆等线上能力,建议显式设置线上默认地域: + +```bash +agentengine config set KSYUN_REGION=cn-beijing-6 +``` + ## Architecture ```mermaid diff --git a/README.zh-CN.md b/README.zh-CN.md index 5720ba56..ff768ef0 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -60,6 +60,12 @@ agentengine web . --no-open agentengine config set OPENAI_BASE_URL=https://api.example.com/v1 ``` +如果需要调用金山云 AgentEngine、Skill Service、知识库或长期记忆等线上能力,建议显式设置线上默认地域: + +```bash +agentengine config set KSYUN_REGION=cn-beijing-6 +``` + ## Architecture ```mermaid diff --git a/public-docs/index.en.md b/public-docs/index.en.md index fd35ddb5..d168a02e 100644 --- a/public-docs/index.en.md +++ b/public-docs/index.en.md @@ -67,6 +67,12 @@ If your model provider is not the default OpenAI endpoint, also set: agentengine config set OPENAI_BASE_URL=https://api.example.com/v1 ``` +If you need Kingsoft Cloud AgentEngine, Skill Service, knowledge base, or long-term memory services, set the default public cloud region explicitly: + +```bash +agentengine config set KSYUN_REGION=cn-beijing-6 +``` + ## Architecture ```mermaid diff --git a/public-docs/index.md b/public-docs/index.md index 30e6584a..41b705fb 100644 --- a/public-docs/index.md +++ b/public-docs/index.md @@ -67,6 +67,12 @@ agentengine web . --no-open agentengine config set OPENAI_BASE_URL=https://api.example.com/v1 ``` +如果需要调用金山云 AgentEngine、Skill Service、知识库或长期记忆等线上能力,建议显式设置线上默认地域: + +```bash +agentengine config set KSYUN_REGION=cn-beijing-6 +``` + ## Architecture ```mermaid diff --git a/tests/test_public_positioning_docs.py b/tests/test_public_positioning_docs.py index 074d7819..3c91a4da 100644 --- a/tests/test_public_positioning_docs.py +++ b/tests/test_public_positioning_docs.py @@ -50,6 +50,7 @@ def test_readmes_position_ksadk_as_runtime_platform(): "Observability", "Deployment", "Community", + "KSYUN_REGION=cn-beijing-6", ) for relative_path in ("README.md", "README.zh-CN.md"): text = _read(relative_path) @@ -71,6 +72,7 @@ def test_english_readme_positions_ksadk_as_runtime_platform(): "Observability", "Deployment", "Community", + "KSYUN_REGION=cn-beijing-6", ) for expected in expected_sections: assert expected in text @@ -90,6 +92,7 @@ def test_docs_homepage_uses_runtime_platform_information_architecture(): "OpenTelemetry", "Hermes", "OpenClaw", + "KSYUN_REGION=cn-beijing-6", ): assert expected in text assert "Agent Development Kit" not in text From a888150b7b0f45b0c2bb300bf8758572fd4a2104 Mon Sep 17 00:00:00 2001 From: xiayu Date: Wed, 10 Jun 2026 07:25:34 +0800 Subject: [PATCH 03/20] docs: remove pre-release wording from public candidate --- CHANGELOG.md | 1 + tests/test_public_positioning_docs.py | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76833ce3..98b0f8b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - **文档信息架构调整**:MkDocs 导航改为 Getting Started / Build / Run / Deploy / Observe / Extend / Reference,更贴近开发者完成任务的路径。 - **Samples 场景入口对齐**:`ksadk-samples` 根 README 改为场景优先,真实映射 Knowledge Assistant、Workflow Agent、Tool-Using Agent 和 Memory-aware Agent;尚未实现的场景只进入 Roadmap。 - **公开元数据修复**:更新 PyPI summary 和包内简介为 Agent Runtime Platform 定位,为后续补丁发布准备干净的 long description。 +- **默认线上地域说明**:公开 README 和文档首页使用 `KSYUN_REGION=cn-beijing-6` 作为线上默认 region 示例,避免用户把非公开或内网配置照搬到公开 demo。 ### 修复 diff --git a/tests/test_public_positioning_docs.py b/tests/test_public_positioning_docs.py index 3c91a4da..c7e2821a 100644 --- a/tests/test_public_positioning_docs.py +++ b/tests/test_public_positioning_docs.py @@ -137,6 +137,7 @@ def iter_labels(items): def test_public_materials_do_not_publish_environment_specific_release_words(): forbidden = ( "pre-online", + "预发", "内部预发 endpoint", "internal pre-release endpoints", "X-Ksc-Region", From af760c881b8ad3a8951fb2689dcd1e56471a516f Mon Sep 17 00:00:00 2001 From: xiayu Date: Wed, 10 Jun 2026 07:43:57 +0800 Subject: [PATCH 04/20] docs: mark 0.6.4 as review candidate --- README.en.md | 2 +- README.md | 2 +- README.zh-CN.md | 2 +- tests/test_public_positioning_docs.py | 4 ++++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.en.md b/README.en.md index d304a402..a7fa5951 100644 --- a/README.en.md +++ b/README.en.md @@ -8,7 +8,7 @@ Build agents once. Run them anywhere. KsADK is the Agent Runtime Platform for AI agents. Build with Google ADK, LangGraph, LangChain, or DeepAgents, then run, debug, expose, observe, and deploy those agents through one runtime experience. -Current version: `0.6.4`. +Candidate version: `0.6.4` (Unreleased, pending user review; use PyPI and GitHub Releases as the source of truth for published versions). - Local Development - Browser Debugging UI diff --git a/README.md b/README.md index ff768ef0..7cca41a9 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Build agents once. Run them anywhere. KsADK is the Agent Runtime Platform for AI agents. 你可以继续使用 Google ADK、LangGraph、LangChain 或 DeepAgents 编写业务 Agent,再用 KsADK 获得统一的本地运行、浏览器调试、OpenAI-Compatible API、沙箱执行、部署和可观测体验。 -当前版本:`0.6.4`。 +候选版本:`0.6.4`(Unreleased,待用户 review;正式发布版本以 PyPI 和 GitHub Release 为准)。 - Local Development - Browser Debugging UI diff --git a/README.zh-CN.md b/README.zh-CN.md index ff768ef0..7cca41a9 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -8,7 +8,7 @@ Build agents once. Run them anywhere. KsADK is the Agent Runtime Platform for AI agents. 你可以继续使用 Google ADK、LangGraph、LangChain 或 DeepAgents 编写业务 Agent,再用 KsADK 获得统一的本地运行、浏览器调试、OpenAI-Compatible API、沙箱执行、部署和可观测体验。 -当前版本:`0.6.4`。 +候选版本:`0.6.4`(Unreleased,待用户 review;正式发布版本以 PyPI 和 GitHub Release 为准)。 - Local Development - Browser Debugging UI diff --git a/tests/test_public_positioning_docs.py b/tests/test_public_positioning_docs.py index c7e2821a..3307d42d 100644 --- a/tests/test_public_positioning_docs.py +++ b/tests/test_public_positioning_docs.py @@ -58,6 +58,8 @@ def test_readmes_position_ksadk_as_runtime_platform(): assert expected in text, f"{relative_path} missing {expected}" assert "Agent Development Kit" not in text assert "KSADK_SKILL_SERVICE_REGION=pre-online" not in text + assert "当前版本:" not in text + assert "候选版本:`0.6.4`" in text def test_english_readme_positions_ksadk_as_runtime_platform(): @@ -78,6 +80,8 @@ def test_english_readme_positions_ksadk_as_runtime_platform(): assert expected in text assert "Agent Development Kit" not in text assert "KSADK_SKILL_SERVICE_REGION=pre-online" not in text + assert "Current version:" not in text + assert "Candidate version: `0.6.4`" in text def test_docs_homepage_uses_runtime_platform_information_architecture(): From b6eb0ce754414599b84aa77da7634e79e8a076b4 Mon Sep 17 00:00:00 2001 From: xiayu Date: Wed, 10 Jun 2026 08:13:30 +0800 Subject: [PATCH 05/20] docs: use PyPI-friendly README architecture diagram --- README.en.md | 31 +++++++++++++++++---------- README.md | 31 +++++++++++++++++---------- README.zh-CN.md | 31 +++++++++++++++++---------- tests/test_public_positioning_docs.py | 4 ++++ 4 files changed, 64 insertions(+), 33 deletions(-) diff --git a/README.en.md b/README.en.md index a7fa5951..d5ee324d 100644 --- a/README.en.md +++ b/README.en.md @@ -68,17 +68,26 @@ agentengine config set KSYUN_REGION=cn-beijing-6 ## Architecture -```mermaid -flowchart TD - Code["Agent Code
ADK / LangGraph / LangChain / DeepAgents"] --> SDK["KsADK SDK
runner adapters + config"] - SDK --> Runtime["Unified Runtime
CLI + Web UI + OpenAI-Compatible API"] - Runtime --> Sandbox["Sandbox
isolated command/code execution"] - Runtime --> Skills["Skills
Skill Space + Skill Runtime"] - Runtime --> Memory["Memory & Knowledge
sessions + LTM + RAG"] - Sandbox --> Engine["AgentEngine"] - Skills --> Engine - Memory --> Engine - Engine --> Backends["Serverless / Hermes / OpenClaw Runtime"] +```text +Agent Code + ADK / LangGraph / LangChain / DeepAgents + | + v +KsADK SDK + runner adapters / config / toolsets + | + v +Unified Runtime + CLI / Web UI / OpenAI-Compatible API + | + +-- Skill Runtime + +-- Workspace Tools + +-- Sandbox Runtime + +-- Memory & Knowledge + | + v +AgentEngine + Serverless / Hermes / OpenClaw Runtime ``` ## Supported Frameworks diff --git a/README.md b/README.md index 7cca41a9..0e34f048 100644 --- a/README.md +++ b/README.md @@ -68,17 +68,26 @@ agentengine config set KSYUN_REGION=cn-beijing-6 ## Architecture -```mermaid -flowchart TD - Code["Agent Code
ADK / LangGraph / LangChain / DeepAgents"] --> SDK["KsADK SDK
runner adapters + config"] - SDK --> Runtime["Unified Runtime
CLI + Web UI + OpenAI-Compatible API"] - Runtime --> Sandbox["Sandbox
isolated command/code execution"] - Runtime --> Skills["Skills
Skill Space + Skill Runtime"] - Runtime --> Memory["Memory & Knowledge
sessions + LTM + RAG"] - Sandbox --> Engine["AgentEngine"] - Skills --> Engine - Memory --> Engine - Engine --> Backends["Serverless / Hermes / OpenClaw Runtime"] +```text +Agent Code + ADK / LangGraph / LangChain / DeepAgents + | + v +KsADK SDK + runner adapters / config / toolsets + | + v +Unified Runtime + CLI / Web UI / OpenAI-Compatible API + | + +-- Skill Runtime + +-- Workspace Tools + +-- Sandbox Runtime + +-- Memory & Knowledge + | + v +AgentEngine + Serverless / Hermes / OpenClaw Runtime ``` ## Supported Frameworks diff --git a/README.zh-CN.md b/README.zh-CN.md index 7cca41a9..0e34f048 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -68,17 +68,26 @@ agentengine config set KSYUN_REGION=cn-beijing-6 ## Architecture -```mermaid -flowchart TD - Code["Agent Code
ADK / LangGraph / LangChain / DeepAgents"] --> SDK["KsADK SDK
runner adapters + config"] - SDK --> Runtime["Unified Runtime
CLI + Web UI + OpenAI-Compatible API"] - Runtime --> Sandbox["Sandbox
isolated command/code execution"] - Runtime --> Skills["Skills
Skill Space + Skill Runtime"] - Runtime --> Memory["Memory & Knowledge
sessions + LTM + RAG"] - Sandbox --> Engine["AgentEngine"] - Skills --> Engine - Memory --> Engine - Engine --> Backends["Serverless / Hermes / OpenClaw Runtime"] +```text +Agent Code + ADK / LangGraph / LangChain / DeepAgents + | + v +KsADK SDK + runner adapters / config / toolsets + | + v +Unified Runtime + CLI / Web UI / OpenAI-Compatible API + | + +-- Skill Runtime + +-- Workspace Tools + +-- Sandbox Runtime + +-- Memory & Knowledge + | + v +AgentEngine + Serverless / Hermes / OpenClaw Runtime ``` ## Supported Frameworks diff --git a/tests/test_public_positioning_docs.py b/tests/test_public_positioning_docs.py index 3307d42d..649c9092 100644 --- a/tests/test_public_positioning_docs.py +++ b/tests/test_public_positioning_docs.py @@ -56,6 +56,8 @@ def test_readmes_position_ksadk_as_runtime_platform(): text = _read(relative_path) for expected in expected_sections: assert expected in text, f"{relative_path} missing {expected}" + assert "```mermaid" not in text + assert "```text" in text assert "Agent Development Kit" not in text assert "KSADK_SKILL_SERVICE_REGION=pre-online" not in text assert "当前版本:" not in text @@ -78,6 +80,8 @@ def test_english_readme_positions_ksadk_as_runtime_platform(): ) for expected in expected_sections: assert expected in text + assert "```mermaid" not in text + assert "```text" in text assert "Agent Development Kit" not in text assert "KSADK_SKILL_SERVICE_REGION=pre-online" not in text assert "Current version:" not in text From 7e936ca67d61a1b9b11177210e4c92fa52de9166 Mon Sep 17 00:00:00 2001 From: xiayu Date: Wed, 10 Jun 2026 08:24:56 +0800 Subject: [PATCH 06/20] docs: remove internal review wording from public docs --- public-docs/contributing/release.en.md | 8 ++++---- public-docs/contributing/release.md | 2 +- public-docs/guides/build-and-package.en.md | 8 ++++---- public-docs/reference/security-boundaries.md | 2 +- tests/test_public_positioning_docs.py | 7 +++++++ 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/public-docs/contributing/release.en.md b/public-docs/contributing/release.en.md index 9e0f6364..feeff4bd 100644 --- a/public-docs/contributing/release.en.md +++ b/public-docs/contributing/release.en.md @@ -6,7 +6,7 @@ The first public release should be prepared from an independent branch and revie 1. Prepare the candidate on an independent branch. 2. Run local tests, packaging checks, artifact audits, and docs build. -3. Push to the internal ezone repository for company review. +3. Push the candidate to the private maintainer review channel. 4. After approval, import the reviewed source into GitHub `main`. 5. Enable GitHub Pages only after public docs CI passes. 6. Create release tags, GitHub release assets, and TestPyPI/PyPI uploads only @@ -14,9 +14,9 @@ The first public release should be prepared from an independent branch and revie 7. Verify published releases and tags with `python3 scripts/check_publication_state.py --phase published --check-release --check-pages`. -GitHub source import must not happen before the internal review gate. The +GitHub source import must not happen before the maintainer review gate. The candidate branch is for review and local gates only; public release assets must -not be created directly from an internal `master` branch or an unsynced +not be created directly from the private development branch or an unsynced `release/public-*` candidate branch. The published-state check also verifies that the imported GitHub repositories contain the expected public source, CI workflow, and Pages workflow marker @@ -84,7 +84,7 @@ Never commit: Before importing real source into GitHub, the approval record must name: -- the exact internal branch or commit reviewed. +- the exact private branch or commit reviewed. - whether publication uses clean export, rewritten history, or full history. - the export manifests or history scan evidence. - the reviewer who approved the sensitive-data boundary. diff --git a/public-docs/contributing/release.md b/public-docs/contributing/release.md index ca9b2b5c..83784d56 100644 --- a/public-docs/contributing/release.md +++ b/public-docs/contributing/release.md @@ -1,6 +1,6 @@ # 发布流程 -公开发布分为内部审核、GitHub 导入、Pages、release 和 PyPI/TestPyPI。 +公开发布分为维护者审核、GitHub 导入、Pages、release 和 PyPI/TestPyPI。 ## 发布前 diff --git a/public-docs/guides/build-and-package.en.md b/public-docs/guides/build-and-package.en.md index f2e23e98..b16ae0a0 100644 --- a/public-docs/guides/build-and-package.en.md +++ b/public-docs/guides/build-and-package.en.md @@ -78,19 +78,19 @@ Release artifacts must not contain: The Python package may include static UI assets needed by `agentengine web`. Editable UI source belongs to `ksadk-web`. -## Internal Review Before Public Push +## Maintainer Review Before Public Push The intended publication sequence is: -1. push the review branch to internal ezone. -2. complete internal maintainer review. +1. push the review branch to the private maintainer review channel. +2. complete maintainer review. 3. import reviewed source into `kingsoftcloud/ksadk-python`. 4. import reviewed UI source into `kingsoftcloud/ksadk-web`. 5. enable GitHub Pages. 6. create GitHub releases. 7. publish PyPI or TestPyPI packages. -Do not skip the internal review step. PyPI credentials, TestPyPI credentials, +Do not skip the maintainer review step. PyPI credentials, TestPyPI credentials, and release tokens must stay outside GitHub source. ## Clean Export Versus Full History diff --git a/public-docs/reference/security-boundaries.md b/public-docs/reference/security-boundaries.md index 11268778..93440fea 100644 --- a/public-docs/reference/security-boundaries.md +++ b/public-docs/reference/security-boundaries.md @@ -30,5 +30,5 @@ Web UI 源码属于独立 `kingsoftcloud/ksadk-web` 仓库。构建静态产物 ## 发布边界 -公开 GitHub source import、Pages、release、PyPI/TestPyPI 上传必须在内部 review +公开 GitHub source import、Pages、release、PyPI/TestPyPI 上传必须在维护者 review 和维护者审批之后执行。审批前公开仓只保留 placeholder。 diff --git a/tests/test_public_positioning_docs.py b/tests/test_public_positioning_docs.py index 649c9092..74ab9b7a 100644 --- a/tests/test_public_positioning_docs.py +++ b/tests/test_public_positioning_docs.py @@ -154,6 +154,13 @@ def test_public_materials_do_not_publish_environment_specific_release_words(): "kspmas-internal", "aicp.inner.api", "maicp.inner", + "internal ezone", + "internal review gate", + "internal maintainer review", + "company review", + "内部 ezone", + "内部审核", + "内部 review", ) for path in _public_markdown_and_config_files(): text = path.read_text(encoding="utf-8") From 8f7f63460ed64ea26a6bebb69f7ce9f2ccdfd6c1 Mon Sep 17 00:00:00 2001 From: xiayu Date: Wed, 10 Jun 2026 08:42:05 +0800 Subject: [PATCH 07/20] docs: generalize public sensitive-word checks --- CHANGELOG.md | 2 +- README.md | 2 +- README.zh-CN.md | 2 +- public-docs/guides/local-web-ui.md | 2 +- tests/test_public_positioning_docs.py | 50 +++++++++++++++------------ 5 files changed, 31 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98b0f8b1..a178eed7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ ### 亮点 -- **公开定位重构**:将项目首页、README 和文档首页从普通 SDK 口径调整为 Agent Runtime Platform,补齐 Why KsADK、30 秒体验、架构图、对比表、Deployment、Observability 和 Community。 +- **公开定位重构**:将项目首页、README 和文档首页从传统 SDK 口径调整为 Agent Runtime Platform,补齐 Why KsADK、30 秒体验、架构图、对比表、Deployment、Observability 和 Community。 - **文档信息架构调整**:MkDocs 导航改为 Getting Started / Build / Run / Deploy / Observe / Extend / Reference,更贴近开发者完成任务的路径。 - **Samples 场景入口对齐**:`ksadk-samples` 根 README 改为场景优先,真实映射 Knowledge Assistant、Workflow Agent、Tool-Using Agent 和 Memory-aware Agent;尚未实现的场景只进入 Roadmap。 - **公开元数据修复**:更新 PyPI summary 和包内简介为 Agent Runtime Platform 定位,为后续补丁发布准备干净的 long description。 diff --git a/README.md b/README.md index 0e34f048..3ffe9533 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ Export once. Observe anywhere. ## 0.6.4 重点 -- 将公开定位从普通 SDK 调整为 Agent Runtime Platform,首页补齐 Why KsADK、30 秒体验、架构图、对比表、Deployment、Observability 和 Community。 +- 将公开定位从传统 Agent SDK 调整为 Agent Runtime Platform,首页补齐 Why KsADK、30 秒体验、架构图、对比表、Deployment、Observability 和 Community。 - 重构文档首页和 MkDocs 导航为 Getting Started / Build / Run / Deploy / Observe / Extend / Reference。 - 清理 README、CHANGELOG、文档和后续 PyPI 元数据中的环境特定表述,避免公开页面出现内部环境名或内部 header。 - 将公开定位和敏感词扫描纳入 `public-preflight`,防止后续回退。 diff --git a/README.zh-CN.md b/README.zh-CN.md index 0e34f048..3ffe9533 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -172,7 +172,7 @@ Export once. Observe anywhere. ## 0.6.4 重点 -- 将公开定位从普通 SDK 调整为 Agent Runtime Platform,首页补齐 Why KsADK、30 秒体验、架构图、对比表、Deployment、Observability 和 Community。 +- 将公开定位从传统 Agent SDK 调整为 Agent Runtime Platform,首页补齐 Why KsADK、30 秒体验、架构图、对比表、Deployment、Observability 和 Community。 - 重构文档首页和 MkDocs 导航为 Getting Started / Build / Run / Deploy / Observe / Extend / Reference。 - 清理 README、CHANGELOG、文档和后续 PyPI 元数据中的环境特定表述,避免公开页面出现内部环境名或内部 header。 - 将公开定位和敏感词扫描纳入 `public-preflight`,防止后续回退。 diff --git a/public-docs/guides/local-web-ui.md b/public-docs/guides/local-web-ui.md index 3357e397..043d0f0f 100644 --- a/public-docs/guides/local-web-ui.md +++ b/public-docs/guides/local-web-ui.md @@ -42,7 +42,7 @@ agentengine web . --model my-model ## 与运行时的关系 -UI 调用本地 KsADK 运行时。普通 SDK 用户安装 wheel 后已经拿到静态 UI 资源。 +UI 调用本地 KsADK 运行时。通过 pip 安装 KsADK wheel 后已经拿到静态 UI 资源。 只有开发 UI 源码时才需要 Node.js。 ```mermaid diff --git a/tests/test_public_positioning_docs.py b/tests/test_public_positioning_docs.py index 74ab9b7a..de264757 100644 --- a/tests/test_public_positioning_docs.py +++ b/tests/test_public_positioning_docs.py @@ -1,6 +1,7 @@ from __future__ import annotations from pathlib import Path +import re import tomllib import yaml @@ -39,6 +40,29 @@ def _public_markdown_and_config_files() -> list[Path]: return files +PUBLIC_FORBIDDEN_PATTERNS = ( + ("pre_release_region", re.compile(r"\bpre[\W_]*online\b", re.IGNORECASE)), + ("private_icp_endpoint", re.compile(r"\b\w*icp[.-]inner[.-]api[.-][\w.-]+\b", re.IGNORECASE)), + ("private_agent_api_endpoint", re.compile(r"\bagent[.-]api[.-]pre\b", re.IGNORECASE)), + ("private_kspmas_endpoint", re.compile(r"\bkspmas[.-]internal\b", re.IGNORECASE)), + ("private_region_header", re.compile(r"\bX[-_]K(?:sc|SC)[-_]Region\b")), + ("private_custom_source_header", re.compile(r"\bX[-_]KSC[-_]CUSTOM[-_]SOURCE\b")), + ( + "private_review_process", + re.compile( + r"\b(?:internal\s+(?:ezone|review\s+gate|maintainer\s+review)|company\s+review)\b", + re.IGNORECASE, + ), + ), + ("private_review_process_zh", re.compile(r"\u5185\u90e8\s*(?:ezone|review|\u5ba1\u6838)")), +) + + +def _assert_no_public_sensitive_patterns(relative_path: str, text: str) -> None: + for label, pattern in PUBLIC_FORBIDDEN_PATTERNS: + assert not pattern.search(text), f"{relative_path} matches {label}: {pattern.pattern}" + + def test_readmes_position_ksadk_as_runtime_platform(): expected_sections = ( "Build agents once. Run them anywhere.", @@ -59,7 +83,7 @@ def test_readmes_position_ksadk_as_runtime_platform(): assert "```mermaid" not in text assert "```text" in text assert "Agent Development Kit" not in text - assert "KSADK_SKILL_SERVICE_REGION=pre-online" not in text + _assert_no_public_sensitive_patterns(relative_path, text) assert "当前版本:" not in text assert "候选版本:`0.6.4`" in text @@ -83,7 +107,7 @@ def test_english_readme_positions_ksadk_as_runtime_platform(): assert "```mermaid" not in text assert "```text" in text assert "Agent Development Kit" not in text - assert "KSADK_SKILL_SERVICE_REGION=pre-online" not in text + _assert_no_public_sensitive_patterns("README.en.md", text) assert "Current version:" not in text assert "Candidate version: `0.6.4`" in text @@ -143,30 +167,10 @@ def iter_labels(items): def test_public_materials_do_not_publish_environment_specific_release_words(): - forbidden = ( - "pre-online", - "预发", - "内部预发 endpoint", - "internal pre-release endpoints", - "X-Ksc-Region", - "X-KSC-CUSTOM-SOURCE", - "agent-api-pre", - "kspmas-internal", - "aicp.inner.api", - "maicp.inner", - "internal ezone", - "internal review gate", - "internal maintainer review", - "company review", - "内部 ezone", - "内部审核", - "内部 review", - ) for path in _public_markdown_and_config_files(): text = path.read_text(encoding="utf-8") relative_path = path.relative_to(ROOT) - for fragment in forbidden: - assert fragment not in text, f"{relative_path} contains {fragment}" + _assert_no_public_sensitive_patterns(str(relative_path), text) def test_package_metadata_is_runtime_platform_positioned_for_patch_candidate(): From c09f4bc55363ab24ee400946249ba1fb1d82c35e Mon Sep 17 00:00:00 2001 From: xiayu Date: Wed, 10 Jun 2026 09:16:08 +0800 Subject: [PATCH 08/20] docs: make public README Chinese-first with visual assets --- CHANGELOG.md | 3 +- README.en.md | 11 + README.md | 101 ++++--- README.zh-CN.md | 101 ++++--- .../assets/ksadk-local-debugging-demo.gif | Bin 0 -> 127843 bytes .../assets/ksadk-runtime-architecture.png | Bin 0 -> 193406 bytes .../assets/ksadk-runtime-architecture.svg | 109 ++++++++ public-docs/index.en.md | 17 +- public-docs/index.md | 89 +++--- scripts/generate_public_assets.py | 257 ++++++++++++++++++ scripts/open_source_audit.py | 1 + scripts/prepare_ksadk_python_export.py | 1 + tests/test_prepare_ksadk_python_export.py | 11 + tests/test_public_positioning_docs.py | 72 +++-- 14 files changed, 606 insertions(+), 167 deletions(-) create mode 100644 public-docs/assets/ksadk-local-debugging-demo.gif create mode 100644 public-docs/assets/ksadk-runtime-architecture.png create mode 100644 public-docs/assets/ksadk-runtime-architecture.svg create mode 100644 scripts/generate_public_assets.py diff --git a/CHANGELOG.md b/CHANGELOG.md index a178eed7..ec919775 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ### 亮点 - **公开定位重构**:将项目首页、README 和文档首页从传统 SDK 口径调整为 Agent Runtime Platform,补齐 Why KsADK、30 秒体验、架构图、对比表、Deployment、Observability 和 Community。 +- **中文优先与视觉化首页**:默认 README 和中文文档首页改为中文主叙述,新增可维护的架构图 PNG/SVG 与本地调试演示 GIF,让首次访问者先看到运行时平台边界和 Web UI 最终效果。 - **文档信息架构调整**:MkDocs 导航改为 Getting Started / Build / Run / Deploy / Observe / Extend / Reference,更贴近开发者完成任务的路径。 - **Samples 场景入口对齐**:`ksadk-samples` 根 README 改为场景优先,真实映射 Knowledge Assistant、Workflow Agent、Tool-Using Agent 和 Memory-aware Agent;尚未实现的场景只进入 Roadmap。 - **公开元数据修复**:更新 PyPI summary 和包内简介为 Agent Runtime Platform 定位,为后续补丁发布准备干净的 long description。 @@ -18,7 +19,7 @@ ### 修复 - 清理 README、CHANGELOG、文档首页和 runtime product 文档中的环境特定表述,避免公开页面出现内部环境名、内部 header 或私有 endpoint 示例。 -- 将公开定位、敏感词扫描和 README 场景入口要求纳入本地门禁,降低后续发布材料回退风险。 +- 将公开定位、视觉资产存在性、中文优先标题、敏感词扫描和 README 场景入口要求纳入本地门禁,降低后续发布材料回退风险。 ### 发布说明 diff --git a/README.en.md b/README.en.md index d5ee324d..308e6285 100644 --- a/README.en.md +++ b/README.en.md @@ -18,6 +18,8 @@ Candidate version: `0.6.4` (Unreleased, pending user review; use PyPI and GitHub - Serverless Deployment - Hermes & OpenClaw Runtime +![KsADK local debugging demo](https://kingsoftcloud.github.io/ksadk-python/assets/ksadk-local-debugging-demo.gif) + ## Why KsADK Most agent frameworks solve agent development. @@ -68,6 +70,13 @@ agentengine config set KSYUN_REGION=cn-beijing-6 ## Architecture +![KsADK Agent Runtime Platform architecture](https://kingsoftcloud.github.io/ksadk-python/assets/ksadk-runtime-architecture.png) + +This diagram shows the public runtime boundary: keep building business agents with ADK, LangGraph, LangChain, or DeepAgents, then use KsADK for one CLI, browser Web UI, OpenAI-Compatible APIs, Skill Runtime, Workspace, Sandbox, memory, knowledge, and deployment backends. + +
+Text architecture + ```text Agent Code ADK / LangGraph / LangChain / DeepAgents @@ -90,6 +99,8 @@ AgentEngine Serverless / Hermes / OpenClaw Runtime ``` +
+ ## Supported Frameworks | Framework | What KsADK adds | diff --git a/README.md b/README.md index 3ffe9533..3ec8c935 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,43 @@ # KsADK -[简体中文](README.md) | [English](README.en.md) +[简体中文(默认)](README.md) | [English](README.en.md) [![zread](https://img.shields.io/badge/Ask_Zread-_.svg?style=flat&color=00b0aa&labelColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTg0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTg0IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjc1ODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDQiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L3N2Zz4K&logoColor=ffffff)](https://zread.ai/kingsoftcloud/ksadk-python) -Build agents once. Run them anywhere. +一次构建 Agent,到处运行。 -KsADK is the Agent Runtime Platform for AI agents. 你可以继续使用 Google ADK、LangGraph、LangChain 或 DeepAgents 编写业务 Agent,再用 KsADK 获得统一的本地运行、浏览器调试、OpenAI-Compatible API、沙箱执行、部署和可观测体验。 +KsADK 是面向 AI Agent 的运行时平台(Agent Runtime Platform)。你可以继续使用 Google ADK、LangGraph、LangChain 或 DeepAgents 编写业务 Agent,再用 KsADK 获得统一的本地运行、浏览器调试、OpenAI-Compatible API、沙箱执行、部署和可观测体验。 + +本仓库默认 README 使用简体中文;英文内容仅作为补充入口维护在 [README.en.md](README.en.md)。 候选版本:`0.6.4`(Unreleased,待用户 review;正式发布版本以 PyPI 和 GitHub Release 为准)。 -- Local Development -- Browser Debugging UI -- OpenAI-Compatible API -- Unified Runtime -- Sandbox Execution -- Serverless Deployment -- Hermes & OpenClaw Runtime +- 本地开发(Local Development) +- 浏览器调试界面(Browser Debugging UI) +- OpenAI 兼容 API(OpenAI-Compatible API) +- 统一运行时(Unified Runtime) +- 沙箱执行(Sandbox Execution) +- Serverless 部署(Serverless Deployment) +- Hermes 与 OpenClaw 运行时 + +![KsADK 本地调试演示](https://kingsoftcloud.github.io/ksadk-python/assets/ksadk-local-debugging-demo.gif) -## Why KsADK +## 为什么需要 KsADK -Most agent frameworks solve agent development. +大多数 Agent 框架主要解决“如何开发 Agent”。 -KsADK solves agent runtime. +KsADK 解决“如何运行、调试、部署和观测 Agent”。 它不替换你的框架,而是在框架之上补齐运行时平台层: -- Development:统一 `agentengine init`、`agentengine config`、`agentengine run`。 -- Debugging:本地 Web UI、会话、附件、workspace 文件和流式输出。 -- Runtime:统一 Runner、OpenAI-Compatible API 和多框架入口。 +- 开发:统一 `agentengine init`、`agentengine config`、`agentengine run`。 +- 调试:本地 Web UI、会话、附件、workspace 文件和流式输出。 +- 运行:统一 Runner、OpenAI-Compatible API 和多框架入口。 - Sandbox:Skill Runtime、Workspace 和 sandbox backend 的隔离执行边界。 -- Deployment:Serverless、Hermes、OpenClaw 和远端 AgentEngine 入口。 -- Observability:OpenTelemetry-first tracing,可对接多种观测后端。 +- 部署:Serverless、Hermes、OpenClaw 和远端 AgentEngine 入口。 +- 可观测:OpenTelemetry-first tracing,可对接多种观测后端。 -Keep using your preferred framework. Get a complete runtime platform. +继续使用你熟悉的框架,同时获得完整的运行时平台能力。 ## 30 秒快速体验 @@ -66,7 +70,14 @@ agentengine config set OPENAI_BASE_URL=https://api.example.com/v1 agentengine config set KSYUN_REGION=cn-beijing-6 ``` -## Architecture +## 架构 + +![KsADK Agent Runtime Platform 架构](https://kingsoftcloud.github.io/ksadk-python/assets/ksadk-runtime-architecture.png) + +这张图展示的是公开运行时边界:业务 Agent 仍然由 ADK、LangGraph、LangChain 或 DeepAgents 编写;KsADK 在上层补齐统一 CLI、Web UI、OpenAI-Compatible API、Skill Runtime、Workspace、Sandbox、记忆、知识库和部署后端。 + +
+查看文本版架构 ```text Agent Code @@ -90,30 +101,32 @@ AgentEngine Serverless / Hermes / OpenClaw Runtime ``` -## Supported Frameworks +
+ +## 支持的框架 -| Framework | KsADK 负责什么 | +| 框架 | KsADK 负责什么 | | --- | --- | | Google ADK | 项目模板、Runner 适配、本地运行、Web UI 调试和部署入口。 | | LangGraph | 图状态入口、工具调用、streaming、Skill Runtime 和 workspace toolsets。 | | LangChain | Runnable/chain 适配、本地 OpenAI-Compatible API 和 tracing。 | | DeepAgents | 项目入口、运行时包装、浏览器调试和部署制品。 | -## Comparison +## 能力对比 -| Capability | ADK | LangGraph | OpenAI Agents SDK | KsADK | +| 能力 | ADK | LangGraph | OpenAI Agents SDK | KsADK | | --- | --- | --- | --- | --- | -| Agent Development | Yes | Yes | Yes | Yes | -| Browser Debugging UI | No | No | No | Yes | -| Unified CLI | No | No | No | Yes | -| OpenAI Compatible API | No | No | Partial | Yes | -| Sandbox Runtime | No | No | No | Yes | -| Deployment Workflow | No | No | No | Yes | -| Multi Runtime Backend | No | No | No | Yes | +| Agent 开发 | 支持 | 支持 | 支持 | 支持 | +| 浏览器调试 UI | 不内置 | 不内置 | 不内置 | 支持 | +| 统一 CLI | 不内置 | 不内置 | 不内置 | 支持 | +| OpenAI 兼容 API | 不内置 | 不内置 | 部分支持 | 支持 | +| 沙箱运行时 | 不内置 | 不内置 | 不内置 | 支持 | +| 部署工作流 | 不内置 | 不内置 | 不内置 | 支持 | +| 多运行时后端 | 不内置 | 不内置 | 不内置 | 支持 | 这张表只比较“项目自带的统一运行时平台能力”。KsADK 的设计目标不是替代这些框架,而是把它们放进同一套运行、调试、部署和观测体验里。 -## Core Capabilities +## 核心能力 - `agentengine init`:创建或导入 Agent 项目。 - `agentengine config`:管理 `.env` 和 `agentengine.yaml`。 @@ -125,19 +138,19 @@ AgentEngine - Sandbox Runtime:通过可配置后端隔离执行命令或代码。 - Hermes & OpenClaw:面向更完整 runtime 后端的部署和更新路径。 -## Examples +## 样例 样例仓库按场景组织,而不是只按技术框架分类: - [KSADK Samples](https://github.com/kingsoftcloud/ksadk-samples) -- Knowledge Assistant:知识库问答和 RAG。 -- Workflow Agent:LangGraph + AgentEngine toolsets。 -- Tool-Using Agent:自定义工具调用。 -- Memory-aware Agent:短期记忆和长期记忆接入。 +- 知识助手(Knowledge Assistant):知识库问答和 RAG。 +- 工作流 Agent(Workflow Agent):LangGraph + AgentEngine toolsets。 +- 工具调用 Agent(Tool-Using Agent):自定义工具调用。 +- 记忆增强 Agent(Memory-aware Agent):短期记忆和长期记忆接入。 每个公开 demo 都应包含中文 README、运行命令、环境变量说明、降级行为和验证问题。 -## Deployment +## 部署 KsADK 支持本地优先的开发路径,也提供经过审核后可使用的部署入口: @@ -149,9 +162,9 @@ agentengine dashboard open Hermes 和 OpenClaw 更新已有实例时默认保留服务端已有 env、storage、network、memory 配置,只在显式传入对应 CLI 参数时覆盖,避免升级镜像时误改用户配置。 -## Observability +## 可观测 -KsADK is OpenTelemetry-native. +KsADK 原生面向 OpenTelemetry 设计。 你可以优先使用标准 OTLP 环境变量: @@ -160,7 +173,7 @@ OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.example.com OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer%20token ``` -Compatible with: +可对接: - Langfuse - Arize @@ -168,7 +181,7 @@ Compatible with: - Grafana - Phoenix -Export once. Observe anywhere. +配置一次,到处观测。 ## 0.6.4 重点 @@ -185,7 +198,7 @@ Export once. Observe anywhere. - OpenClaw / Hermes 更新已有实例时默认保留服务端已有 env、storage、network、memory 配置。 - `ksadk.toolsets`、Tool Gateway、Skill Runtime 与 Skill Service 相关文件纳入发布包,LangGraph demo 可在干净安装后绑定 AgentEngine 内置工具。 -## Documentation +## 文档 - 文档: - 中文文档: @@ -193,7 +206,7 @@ Export once. Observe anywhere. - 命令行参考: - OpenAI-Compatible API: -## Community +## 社区 - 仓库: - Wiki: diff --git a/README.zh-CN.md b/README.zh-CN.md index 3ffe9533..3ec8c935 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,39 +1,43 @@ # KsADK -[简体中文](README.md) | [English](README.en.md) +[简体中文(默认)](README.md) | [English](README.en.md) [![zread](https://img.shields.io/badge/Ask_Zread-_.svg?style=flat&color=00b0aa&labelColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTg0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTg0IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjc1ODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDQiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L3N2Zz4K&logoColor=ffffff)](https://zread.ai/kingsoftcloud/ksadk-python) -Build agents once. Run them anywhere. +一次构建 Agent,到处运行。 -KsADK is the Agent Runtime Platform for AI agents. 你可以继续使用 Google ADK、LangGraph、LangChain 或 DeepAgents 编写业务 Agent,再用 KsADK 获得统一的本地运行、浏览器调试、OpenAI-Compatible API、沙箱执行、部署和可观测体验。 +KsADK 是面向 AI Agent 的运行时平台(Agent Runtime Platform)。你可以继续使用 Google ADK、LangGraph、LangChain 或 DeepAgents 编写业务 Agent,再用 KsADK 获得统一的本地运行、浏览器调试、OpenAI-Compatible API、沙箱执行、部署和可观测体验。 + +本仓库默认 README 使用简体中文;英文内容仅作为补充入口维护在 [README.en.md](README.en.md)。 候选版本:`0.6.4`(Unreleased,待用户 review;正式发布版本以 PyPI 和 GitHub Release 为准)。 -- Local Development -- Browser Debugging UI -- OpenAI-Compatible API -- Unified Runtime -- Sandbox Execution -- Serverless Deployment -- Hermes & OpenClaw Runtime +- 本地开发(Local Development) +- 浏览器调试界面(Browser Debugging UI) +- OpenAI 兼容 API(OpenAI-Compatible API) +- 统一运行时(Unified Runtime) +- 沙箱执行(Sandbox Execution) +- Serverless 部署(Serverless Deployment) +- Hermes 与 OpenClaw 运行时 + +![KsADK 本地调试演示](https://kingsoftcloud.github.io/ksadk-python/assets/ksadk-local-debugging-demo.gif) -## Why KsADK +## 为什么需要 KsADK -Most agent frameworks solve agent development. +大多数 Agent 框架主要解决“如何开发 Agent”。 -KsADK solves agent runtime. +KsADK 解决“如何运行、调试、部署和观测 Agent”。 它不替换你的框架,而是在框架之上补齐运行时平台层: -- Development:统一 `agentengine init`、`agentengine config`、`agentengine run`。 -- Debugging:本地 Web UI、会话、附件、workspace 文件和流式输出。 -- Runtime:统一 Runner、OpenAI-Compatible API 和多框架入口。 +- 开发:统一 `agentengine init`、`agentengine config`、`agentengine run`。 +- 调试:本地 Web UI、会话、附件、workspace 文件和流式输出。 +- 运行:统一 Runner、OpenAI-Compatible API 和多框架入口。 - Sandbox:Skill Runtime、Workspace 和 sandbox backend 的隔离执行边界。 -- Deployment:Serverless、Hermes、OpenClaw 和远端 AgentEngine 入口。 -- Observability:OpenTelemetry-first tracing,可对接多种观测后端。 +- 部署:Serverless、Hermes、OpenClaw 和远端 AgentEngine 入口。 +- 可观测:OpenTelemetry-first tracing,可对接多种观测后端。 -Keep using your preferred framework. Get a complete runtime platform. +继续使用你熟悉的框架,同时获得完整的运行时平台能力。 ## 30 秒快速体验 @@ -66,7 +70,14 @@ agentengine config set OPENAI_BASE_URL=https://api.example.com/v1 agentengine config set KSYUN_REGION=cn-beijing-6 ``` -## Architecture +## 架构 + +![KsADK Agent Runtime Platform 架构](https://kingsoftcloud.github.io/ksadk-python/assets/ksadk-runtime-architecture.png) + +这张图展示的是公开运行时边界:业务 Agent 仍然由 ADK、LangGraph、LangChain 或 DeepAgents 编写;KsADK 在上层补齐统一 CLI、Web UI、OpenAI-Compatible API、Skill Runtime、Workspace、Sandbox、记忆、知识库和部署后端。 + +
+查看文本版架构 ```text Agent Code @@ -90,30 +101,32 @@ AgentEngine Serverless / Hermes / OpenClaw Runtime ``` -## Supported Frameworks +
+ +## 支持的框架 -| Framework | KsADK 负责什么 | +| 框架 | KsADK 负责什么 | | --- | --- | | Google ADK | 项目模板、Runner 适配、本地运行、Web UI 调试和部署入口。 | | LangGraph | 图状态入口、工具调用、streaming、Skill Runtime 和 workspace toolsets。 | | LangChain | Runnable/chain 适配、本地 OpenAI-Compatible API 和 tracing。 | | DeepAgents | 项目入口、运行时包装、浏览器调试和部署制品。 | -## Comparison +## 能力对比 -| Capability | ADK | LangGraph | OpenAI Agents SDK | KsADK | +| 能力 | ADK | LangGraph | OpenAI Agents SDK | KsADK | | --- | --- | --- | --- | --- | -| Agent Development | Yes | Yes | Yes | Yes | -| Browser Debugging UI | No | No | No | Yes | -| Unified CLI | No | No | No | Yes | -| OpenAI Compatible API | No | No | Partial | Yes | -| Sandbox Runtime | No | No | No | Yes | -| Deployment Workflow | No | No | No | Yes | -| Multi Runtime Backend | No | No | No | Yes | +| Agent 开发 | 支持 | 支持 | 支持 | 支持 | +| 浏览器调试 UI | 不内置 | 不内置 | 不内置 | 支持 | +| 统一 CLI | 不内置 | 不内置 | 不内置 | 支持 | +| OpenAI 兼容 API | 不内置 | 不内置 | 部分支持 | 支持 | +| 沙箱运行时 | 不内置 | 不内置 | 不内置 | 支持 | +| 部署工作流 | 不内置 | 不内置 | 不内置 | 支持 | +| 多运行时后端 | 不内置 | 不内置 | 不内置 | 支持 | 这张表只比较“项目自带的统一运行时平台能力”。KsADK 的设计目标不是替代这些框架,而是把它们放进同一套运行、调试、部署和观测体验里。 -## Core Capabilities +## 核心能力 - `agentengine init`:创建或导入 Agent 项目。 - `agentengine config`:管理 `.env` 和 `agentengine.yaml`。 @@ -125,19 +138,19 @@ AgentEngine - Sandbox Runtime:通过可配置后端隔离执行命令或代码。 - Hermes & OpenClaw:面向更完整 runtime 后端的部署和更新路径。 -## Examples +## 样例 样例仓库按场景组织,而不是只按技术框架分类: - [KSADK Samples](https://github.com/kingsoftcloud/ksadk-samples) -- Knowledge Assistant:知识库问答和 RAG。 -- Workflow Agent:LangGraph + AgentEngine toolsets。 -- Tool-Using Agent:自定义工具调用。 -- Memory-aware Agent:短期记忆和长期记忆接入。 +- 知识助手(Knowledge Assistant):知识库问答和 RAG。 +- 工作流 Agent(Workflow Agent):LangGraph + AgentEngine toolsets。 +- 工具调用 Agent(Tool-Using Agent):自定义工具调用。 +- 记忆增强 Agent(Memory-aware Agent):短期记忆和长期记忆接入。 每个公开 demo 都应包含中文 README、运行命令、环境变量说明、降级行为和验证问题。 -## Deployment +## 部署 KsADK 支持本地优先的开发路径,也提供经过审核后可使用的部署入口: @@ -149,9 +162,9 @@ agentengine dashboard open Hermes 和 OpenClaw 更新已有实例时默认保留服务端已有 env、storage、network、memory 配置,只在显式传入对应 CLI 参数时覆盖,避免升级镜像时误改用户配置。 -## Observability +## 可观测 -KsADK is OpenTelemetry-native. +KsADK 原生面向 OpenTelemetry 设计。 你可以优先使用标准 OTLP 环境变量: @@ -160,7 +173,7 @@ OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.example.com OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer%20token ``` -Compatible with: +可对接: - Langfuse - Arize @@ -168,7 +181,7 @@ Compatible with: - Grafana - Phoenix -Export once. Observe anywhere. +配置一次,到处观测。 ## 0.6.4 重点 @@ -185,7 +198,7 @@ Export once. Observe anywhere. - OpenClaw / Hermes 更新已有实例时默认保留服务端已有 env、storage、network、memory 配置。 - `ksadk.toolsets`、Tool Gateway、Skill Runtime 与 Skill Service 相关文件纳入发布包,LangGraph demo 可在干净安装后绑定 AgentEngine 内置工具。 -## Documentation +## 文档 - 文档: - 中文文档: @@ -193,7 +206,7 @@ Export once. Observe anywhere. - 命令行参考: - OpenAI-Compatible API: -## Community +## 社区 - 仓库: - Wiki: diff --git a/public-docs/assets/ksadk-local-debugging-demo.gif b/public-docs/assets/ksadk-local-debugging-demo.gif new file mode 100644 index 0000000000000000000000000000000000000000..2b5be4446e52df5064fb58d4f26ff6258fba4533 GIT binary patch literal 127843 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

Hi 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