docs: publish architecture and experiment portal
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
# K1412 Agent documentation
|
||||
|
||||
This directory is the canonical technical record for K1412 Agent. The public
|
||||
documentation portal at <https://agent.k1412.top/doc/> is a curated rendering
|
||||
of the same design. When behavior, infrastructure, or an experiment changes,
|
||||
update the relevant Markdown document and the portal snapshot in the same
|
||||
commit.
|
||||
|
||||
## Start here
|
||||
|
||||
| Document | Audience | What it answers |
|
||||
| --- | --- | --- |
|
||||
| [Architecture](architecture.md) | Everyone | What runs where, and why are the boundaries drawn this way? |
|
||||
| [Agent loop](agent-loop.md) | Agent researchers and backend engineers | How do context, tools, scheduling, evidence, memory, and child Agents work? |
|
||||
| [Experiment system](experiments.md) | Agent researchers | How do we change the loop without losing comparability or production safety? |
|
||||
| [Project history](project-history.md) | Maintainers | Which product and architecture decisions have already been made? |
|
||||
| [Open WebUI integration](openwebui-integration.md) | Frontend and platform engineers | What belongs to Open WebUI, and what remains K1412-owned? |
|
||||
| [Security model](security.md) | Security and platform engineers | How are users, credentials, workspaces, and Docker separated? |
|
||||
| [Infrastructure map](infrastructure.md) | Operators | Which services are shared infrastructure and which are Agent core? |
|
||||
| [Development and verification](development.md) | Contributors | How do I run, test, and safely change the system? |
|
||||
| [Operations runbook](operations.md) | Operators | How is production built, deployed, verified, backed up, and migrated? |
|
||||
|
||||
## Current product contract
|
||||
|
||||
- There is one user-facing mode: the K1412 Agent loop. The earlier Chat/Work
|
||||
split was removed deliberately.
|
||||
- Open WebUI owns accounts, sessions, approval, conversation storage, and the
|
||||
chat shell. K1412 owns Agent behavior.
|
||||
- Four server-defined model choices are exposed: Luna, Terra, Sol, and
|
||||
DeepSeek V4 Pro. Model identity and thinking capability are displayed
|
||||
separately.
|
||||
- Every Open WebUI user receives an isolated Docker container, network, and
|
||||
persistent volume on the dedicated physical execution host.
|
||||
- Generated files can be browsed and downloaded through the authenticated Web
|
||||
UI. Internal dependency directories are hidden.
|
||||
- Provider credentials, internal prompts, Docker access, SSH configuration,
|
||||
and tool-service credentials are never browser-configurable.
|
||||
|
||||
## What is experimental
|
||||
|
||||
The stable platform boundary is authentication, user/workspace isolation,
|
||||
durable storage, and the public OpenAI-compatible Runtime API. The intended
|
||||
experimental surface is:
|
||||
|
||||
- context selection and compaction;
|
||||
- memory retrieval and lifecycle;
|
||||
- tool descriptions, normalization, and routing;
|
||||
- parallel scheduling and mutation serialization;
|
||||
- child-Agent delegation policy;
|
||||
- evidence and completion gates;
|
||||
- recovery prompts and retry policy;
|
||||
- model routing and per-tier budgets.
|
||||
|
||||
Every experiment should be versioned in run events and evaluated against a
|
||||
fixed task set before production rollout. See [experiments.md](experiments.md).
|
||||
@@ -0,0 +1,223 @@
|
||||
# Agent loop implementation
|
||||
|
||||
## Purpose
|
||||
|
||||
The K1412 loop turns a model completion API into an accountable coding Agent.
|
||||
Its primary rule is simple: a textual claim is not proof that work happened.
|
||||
Files, commands, reports, and tests must be backed by successful tool events
|
||||
from the current run.
|
||||
|
||||
The current event metadata identifies the implementation as:
|
||||
|
||||
- strategy: `agent-loop-v3`;
|
||||
- scheduler: `safe-parallel-v1`;
|
||||
- context policy: `recent-visible-v1`.
|
||||
|
||||
These identifiers are part of the experiment contract, not marketing version
|
||||
numbers. Change them when behavior changes in a way that can affect evaluation.
|
||||
|
||||
## Run state machine
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> BuildContext
|
||||
BuildContext --> RequestModel
|
||||
RequestModel --> ValidateCalls: tool calls
|
||||
RequestModel --> CheckCompletion: no tool calls
|
||||
ValidateCalls --> Schedule
|
||||
Schedule --> Execute
|
||||
Execute --> RecordEvidence
|
||||
RecordEvidence --> RequestModel
|
||||
CheckCompletion --> RequestModel: evidence missing and budget remains
|
||||
CheckCompletion --> Completed: evidence sufficient
|
||||
CheckCompletion --> Unverified: evidence missing and retry budget exhausted
|
||||
Completed --> [*]
|
||||
Unverified --> [*]
|
||||
```
|
||||
|
||||
Every top-level run receives a unique `run_id`. All events include the user,
|
||||
chat, monotonic sequence, timestamp, event type, and a sanitized payload.
|
||||
|
||||
## Context policy
|
||||
|
||||
`ContextPolicy.prepare`:
|
||||
|
||||
1. accepts only system, developer, user, and assistant messages;
|
||||
2. strips rendered `<details type="tool_calls">` blocks from old assistant
|
||||
messages so UI markup is not fed back as model context;
|
||||
3. prepends the K1412 system contract;
|
||||
4. appends up to eight durable user memories as context, explicitly not as
|
||||
higher-priority instructions;
|
||||
5. walks visible messages newest-first until the model's character budget is
|
||||
reached;
|
||||
6. records how many old messages were dropped.
|
||||
|
||||
The policy is intentionally simple and inspectable. It does not yet summarize
|
||||
old conversation branches, retrieve semantic workspace context, or estimate
|
||||
provider-specific tokenization. Those are future experiment candidates.
|
||||
|
||||
## Model contract
|
||||
|
||||
`ModelSpec` is the server-side source of truth for:
|
||||
|
||||
- public and provider model IDs;
|
||||
- provider selection;
|
||||
- thinking capability and display label;
|
||||
- reasoning effort when the provider supports it;
|
||||
- maximum output tokens;
|
||||
- maximum loop iterations;
|
||||
- context character budget.
|
||||
|
||||
Luna, Terra, and Sol are separate local models with boolean thinking support;
|
||||
they are not three effort settings for one model. DeepSeek V4 Pro uses the
|
||||
DeepSeek provider with thinking enabled and `reasoning_effort=max`.
|
||||
|
||||
Runtime preserves provider `reasoning_content` across tool turns when required
|
||||
for protocol correctness, but does not publish hidden reasoning as user-facing
|
||||
content.
|
||||
|
||||
## Tool catalog
|
||||
|
||||
Workspace tools:
|
||||
|
||||
- status, list, read, search, write, and patch files;
|
||||
- execute foreground commands;
|
||||
- inspect Git status and diff;
|
||||
- start, poll, and cancel background processes.
|
||||
|
||||
Runtime state tools:
|
||||
|
||||
- update a per-chat plan;
|
||||
- remember, recall, and forget durable user memory.
|
||||
|
||||
Delegation tool:
|
||||
|
||||
- start one bounded child Agent with a role, task, and explicit write policy.
|
||||
|
||||
Tool schemas use `additionalProperties: false` so malformed model arguments
|
||||
fail early. Arguments are normalized before policy checks. Content and patch
|
||||
bodies are omitted from public run-event payloads.
|
||||
|
||||
## Intent-based tool selection
|
||||
|
||||
The root loop does not always send every tool. Lightweight request classifiers
|
||||
detect whether the task concerns artifacts, execution, source files, reports,
|
||||
comparisons, processes, Git, memory, or delegation. The selected catalog keeps
|
||||
the model's tool decision smaller while retaining the core workspace tools.
|
||||
|
||||
This is heuristic routing, not authorization. Gateway remains the enforcement
|
||||
boundary.
|
||||
|
||||
## Scheduler
|
||||
|
||||
Each model response can request at most eight tool calls. Calls are parsed in
|
||||
their original order and divided into consecutive groups:
|
||||
|
||||
- tools marked `parallel_safe` execute concurrently;
|
||||
- mutations and other non-parallel tools execute serially;
|
||||
- read-only child Agents may run in parallel;
|
||||
- a child with write access is serialized;
|
||||
- child Agents cannot delegate again.
|
||||
|
||||
Gateway also serializes workspace mutations per user. This second lock is
|
||||
important because multiple Runtime requests or browser actions can address the
|
||||
same workspace.
|
||||
|
||||
The scheduler preserves result order even when a parallel group completes out
|
||||
of order.
|
||||
|
||||
## Defensive normalization and retry guards
|
||||
|
||||
The loop repairs a small set of common model formatting mistakes, then applies
|
||||
policy:
|
||||
|
||||
- reject bare interactive commands such as `python3`, `bash`, or `node`;
|
||||
- reject attempts to run documentation/data files as executable source;
|
||||
- reject syntactically invalid complete Python files before writing;
|
||||
- decode repeated escaped source-layout newlines produced by weak models;
|
||||
- skip identical successful writes;
|
||||
- block an identical failed write until content changes;
|
||||
- block an unchanged failed command until a mutation or materially different
|
||||
diagnostic occurs;
|
||||
- deduplicate repeated commands in one batch;
|
||||
- cap generation, iteration, and tool-batch sizes.
|
||||
|
||||
At the execution layer, Bash runs with `pipefail` and returns the true exit
|
||||
code. Foreground tools default to a 900-second ceiling; background processes
|
||||
have explicit start/poll/cancel lifecycle.
|
||||
|
||||
## Evidence-gated completion
|
||||
|
||||
The loop derives required evidence from the user request.
|
||||
|
||||
| Request shape | Minimum evidence |
|
||||
| --- | --- |
|
||||
| Concrete artifact | A successful file mutation and a later successful verification |
|
||||
| Execute/test/analyze | At least one successful execution or inspection |
|
||||
| Source-code request | A separate executable source file |
|
||||
| Report request | A separate report written after execution |
|
||||
| Benchmark/comparison report | Exact numeric measurements copied from successful execution output |
|
||||
|
||||
Verification includes a later file read, Git diff/status, command execution, or
|
||||
background-process poll. A failed command remains unresolved until a later
|
||||
execution succeeds.
|
||||
|
||||
If a model tries to finish too early, Runtime emits `completion.rejected`,
|
||||
returns a focused recovery instruction to the model, and continues. After
|
||||
repeated rejected checkpoints or iteration exhaustion, Runtime returns an
|
||||
explicit incomplete result instead of laundering an unverified claim into a
|
||||
success.
|
||||
|
||||
## Delegation
|
||||
|
||||
A root Agent can delegate a bounded independent task. The child receives:
|
||||
|
||||
- a role and exact task;
|
||||
- a reduced iteration budget of at most eight;
|
||||
- no delegation tool;
|
||||
- read-only tools unless write access was explicitly requested.
|
||||
|
||||
Child events share the root run stream with an increased `depth`. The current
|
||||
implementation is recursive execution inside one Runtime process, not a
|
||||
distributed queue or a persistent autonomous worker.
|
||||
|
||||
## Memory and plans
|
||||
|
||||
Durable memories are scoped by user ID. Recall is currently recency-first with
|
||||
optional case-insensitive substring filtering. Plans are scoped by user and
|
||||
chat and allow at most one `in_progress` item.
|
||||
|
||||
Memory is useful but intentionally conservative: the system does not
|
||||
automatically extract facts from every conversation and does not yet perform
|
||||
embedding retrieval, confidence scoring, expiry, or conflict resolution.
|
||||
|
||||
## Run event model
|
||||
|
||||
Important event types include:
|
||||
|
||||
- `run.created`, `context.built`, `run.completed`, `run.failed`,
|
||||
`run.cancelled`;
|
||||
- `model.requested`, `model.responded`;
|
||||
- `tool.started`, `tool.completed`, `tool.batch_limited`;
|
||||
- `completion.rejected`, `completion.unverified`;
|
||||
- `agent.spawned`, `agent.completed`.
|
||||
|
||||
The event stream powers UI detail blocks today and is the basis for future
|
||||
replay, evaluation, cost analysis, and A/B assignment. Events store public
|
||||
arguments and concise summaries, not credentials, full write bodies, or hidden
|
||||
reasoning.
|
||||
|
||||
## Known limitations
|
||||
|
||||
- Context compaction drops old messages instead of summarizing them.
|
||||
- Memory retrieval is lexical rather than semantic.
|
||||
- Tool intent classifiers are regular-expression based.
|
||||
- The scheduler parallelizes only consecutive safe calls and has no resource
|
||||
cost model.
|
||||
- Child Agents are not durable across Runtime restarts.
|
||||
- Experiment assignment and aggregate dashboards are not yet implemented.
|
||||
- Provider token accounting is retained when returned but is not yet converted
|
||||
into a unified cost model.
|
||||
|
||||
These are deliberate experiment targets, documented in
|
||||
[experiments.md](experiments.md).
|
||||
+164
-53
@@ -1,74 +1,185 @@
|
||||
# Architecture
|
||||
|
||||
## Single Agent path
|
||||
## Design objective
|
||||
|
||||
Open WebUI owns authenticated users, conversation history, and rendering.
|
||||
Every normal model request is delegated to the K1412 Runtime. There is no
|
||||
second Chat loop and no per-conversation mode state.
|
||||
K1412 Agent is a multi-user web coding Agent whose loop can be changed
|
||||
independently of its account system and user interface. The architecture keeps
|
||||
the high-cost experimental surface small: researchers should be able to change
|
||||
context, memory, scheduling, tools, delegation, or completion policy without
|
||||
forking authentication, chat history, Docker lifecycle, or the whole frontend.
|
||||
|
||||
## Agent loop
|
||||
The system deliberately has one Agent path. The earlier idea of a lightweight
|
||||
Chat loop beside a custom Work loop was removed because it duplicated product
|
||||
behavior, confused model selection, and increased the amount of frontend and
|
||||
backend code that had to remain compatible.
|
||||
|
||||
The first strategy is intentionally modular:
|
||||
## System context
|
||||
|
||||
- `ModelProvider` owns provider transport.
|
||||
- `ContextPolicy` owns visible-message cleanup and compaction.
|
||||
- `ToolRegistry` owns tool schemas and dispatch.
|
||||
- `AgentLoop` owns iteration, safe parallel scheduling, and delegation.
|
||||
- `RuntimeStore` owns events, plans, and durable Agent memory.
|
||||
- `ExecutionProvider` owns local or SSH Docker execution.
|
||||
```mermaid
|
||||
flowchart LR
|
||||
U["Browser user"] --> P["DNS, TLS and Nginx Proxy Manager"]
|
||||
P --> W["Open WebUI<br/>auth, RBAC, history, UI"]
|
||||
W --> R["Agent Runtime<br/>loop, context, memory, model routing"]
|
||||
R --> M["Model providers<br/>K1412 API or DeepSeek"]
|
||||
R --> G["Workspace Gateway<br/>identity and execution policy"]
|
||||
G -->|Tailscale + SSH Docker| X["Per-user workspace container<br/>home-node-itx"]
|
||||
W --> DB["PostgreSQL<br/>users and chats"]
|
||||
R --> DB
|
||||
W --> Q["Redis<br/>coordination"]
|
||||
```
|
||||
|
||||
Every run records its model ID, strategy version, scheduler version, context
|
||||
policy, model/tool events, failures, and completion. This event stream is the
|
||||
foundation for replay, evaluation, and future experiment assignment.
|
||||
Only Web is publicly reachable. Runtime, Gateway, PostgreSQL, and Redis live on
|
||||
private Compose networks. Workspace containers run on a separate physical
|
||||
Docker host, receive no application secrets, and expose no host ports.
|
||||
|
||||
Luna, Terra, and Sol are three independent Ollama models. Each advertises
|
||||
boolean thinking support, but none advertises adjustable reasoning effort.
|
||||
DeepSeek V4 Pro is a fourth model configured with thinking enabled and maximum
|
||||
reasoning effort. Provider selection and credentials remain server-side.
|
||||
Thinking state is preserved across tool turns when the provider requires the
|
||||
assistant's `reasoning_content` to be returned with following tool results.
|
||||
The Agent never publishes hidden reasoning as its own user-facing output.
|
||||
## Responsibility boundaries
|
||||
|
||||
Completion is evidence-gated. Requests for scripts, reports, code, or
|
||||
other concrete artifacts are not accepted as complete until a file mutation
|
||||
has succeeded and a later read, diff, or command has verified the latest
|
||||
mutation. Bare interactive shell commands are rejected. If the iteration
|
||||
budget is exhausted without evidence, Runtime returns an explicit incomplete
|
||||
checkpoint instead of repeating an unverified model claim.
|
||||
| Layer | Owns | Must not own |
|
||||
| --- | --- | --- |
|
||||
| Open WebUI | Registration, login, sessions, admin approval, RBAC, chat persistence, rendering | Agent scheduling, provider secrets, Docker access |
|
||||
| Agent Runtime | Model catalog, context policy, Agent loop, tools, scheduling, delegation, memory, plans, run events, evidence gates | Browser sessions, Docker socket |
|
||||
| Workspace Gateway | Signed identity enforcement, workspace path policy, per-user locks, Docker lifecycle, file delivery | Model calls, public authentication UI |
|
||||
| Workspace container | User code, dependencies, generated files, command execution | Other users' data, service credentials, Docker socket |
|
||||
| PostgreSQL | Open WebUI durable state plus Runtime events, plans, and memories | Execution |
|
||||
| Shared infrastructure | TLS, registry, source hosting, private routing, model serving | Agent behavior |
|
||||
|
||||
Read-only tools and read-only child Agents may run concurrently. Workspace
|
||||
mutations are serialized. A child Agent cannot delegate again, and read-only
|
||||
children receive only read-only tools.
|
||||
This separation lets the Web UI be upgraded on its own schedule while the
|
||||
Agent loop can iterate frequently.
|
||||
|
||||
## Execution providers
|
||||
## Request lifecycle
|
||||
|
||||
`local-docker` connects the Workspace Gateway to the local Docker daemon.
|
||||
`ssh-docker` connects the same Docker SDK operations to a remote physical
|
||||
machine through SSH. Both create the same workspace image, persistent per-user
|
||||
volume, and dedicated per-user bridge network, so moving execution off the web
|
||||
host changes configuration rather than Agent behavior.
|
||||
### Agent request
|
||||
|
||||
For SSH mode, layer `compose.ssh.yaml` over the development Compose file, or
|
||||
`deploy/docker-compose.ssh.yml` over the two production Compose files. The
|
||||
override removes the local Docker socket and mounts only the selected SSH
|
||||
configuration directory read-only.
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant B as Browser
|
||||
participant W as Open WebUI
|
||||
participant R as Runtime
|
||||
participant M as Model provider
|
||||
participant G as Gateway
|
||||
participant X as User workspace
|
||||
|
||||
Only Open WebUI publishes a host port. Runtime, Gateway, Postgres, and Redis
|
||||
remain unpublishing services. Runtime and Gateway also join an egress-only
|
||||
bridge so the model API and a future SSH Docker host are reachable without
|
||||
exposing either service on the host.
|
||||
B->>W: Authenticated chat request
|
||||
W->>R: OpenAI-compatible request + service key + signed user identity
|
||||
R->>R: Verify identity, build context, record run.created
|
||||
loop Until evidence-backed completion or budget exhausted
|
||||
R->>M: Recent context + tools + provider policy
|
||||
M-->>R: Assistant content and/or tool calls
|
||||
R->>R: Normalize, validate, limit, and schedule calls
|
||||
R->>G: Tool request + service key + freshly signed identity
|
||||
G->>G: Verify identity and bind user workspace
|
||||
G->>X: Execute with resource and path constraints
|
||||
X-->>G: Exit code, output, or file result
|
||||
G-->>R: Structured tool result
|
||||
R->>R: Persist events and evaluate completion evidence
|
||||
end
|
||||
R-->>W: SSE answer and completed tool detail blocks
|
||||
W-->>B: Rendered Agent response
|
||||
```
|
||||
|
||||
## Workspace file path
|
||||
The identity sent by Open WebUI is verified once when Runtime accepts the
|
||||
request. Runtime then signs the already verified identity again for every
|
||||
Gateway call. This prevents a long Agent run from reusing an identity token
|
||||
that expired while the model or a tool was working.
|
||||
|
||||
### Workspace file request
|
||||
|
||||
```text
|
||||
browser with Open WebUI session
|
||||
-> /api/v1/k1412/workspace/*
|
||||
-> Open WebUI backend verifies the user
|
||||
-> backend mints a short-lived signed identity JWT
|
||||
-> Workspace Gateway verifies service key + user JWT
|
||||
-> provider selects only that user's hashed container and volume
|
||||
-> Open WebUI verifies the logged-in user
|
||||
-> Web signs a short-lived user identity
|
||||
-> Gateway verifies service key + signed identity
|
||||
-> Gateway selects only the hashed container and volume for that user
|
||||
-> browse, download, or streamed archive response
|
||||
```
|
||||
|
||||
The file API exposes read-only browse, file download, and streamed directory
|
||||
archive operations. Paths pass through the same `/workspace` normalization as
|
||||
Agent tools. The browser never talks to Gateway or Docker directly.
|
||||
The browser never receives a Gateway service key and never connects to Docker.
|
||||
|
||||
## Runtime internals
|
||||
|
||||
Runtime is an OpenAI-compatible provider from Open WebUI's point of view, but
|
||||
normal chat completions are implemented by the K1412 loop:
|
||||
|
||||
- `ModelProvider` translates the internal model spec to a provider request and
|
||||
normalizes streamed completion responses.
|
||||
- `ContextPolicy` removes rendered tool-detail markup, prepends the system
|
||||
contract and durable memories, and keeps the newest visible messages within
|
||||
a per-model character budget.
|
||||
- `ToolRegistry` declares tool schemas and routes workspace tools to Gateway or
|
||||
state tools to `RuntimeStore`.
|
||||
- `AgentLoop` owns iteration, tool normalization, validation, scheduling,
|
||||
recovery, delegation, and evidence-gated completion.
|
||||
- `RuntimeStore` persists run events, per-chat plans, and user memories.
|
||||
|
||||
More detail is in [agent-loop.md](agent-loop.md).
|
||||
|
||||
## Workspace architecture
|
||||
|
||||
`local-docker` and `ssh-docker` implement the same `ExecutionProvider`
|
||||
contract. Production uses `ssh-docker`: Gateway talks to Docker on
|
||||
`home-node-itx` through a dedicated SSH configuration mounted read-only.
|
||||
|
||||
Each immutable Open WebUI user ID maps to a SHA-256-derived workspace ID and
|
||||
therefore to exactly one:
|
||||
|
||||
- container named `k1412-ws-<workspace-id>`;
|
||||
- named volume `k1412-ws-data-<workspace-id>`;
|
||||
- bridge network `k1412-ws-net-<workspace-id>`.
|
||||
|
||||
Containers run as UID/GID 1000 with a read-only root filesystem, all Linux
|
||||
capabilities dropped, `no-new-privileges`, PID/CPU/memory limits, no Docker
|
||||
socket, and no published ports. `/workspace` is the only persistent writable
|
||||
filesystem. `/tmp` is writable but mounted `noexec`.
|
||||
|
||||
Python environments live at `/workspace/.venv`. User-level home and package
|
||||
caches live below `/workspace/.agent`. The image puts the virtual environment
|
||||
and user binary directories first on `PATH`. Commands run under Bash with
|
||||
`pipefail`, so a failed install cannot be hidden by a successful `tail` or
|
||||
similar pipeline stage.
|
||||
|
||||
When `WORKSPACE_IMAGE` changes to a new immutable tag, Gateway replaces a stale
|
||||
container on its next access but reattaches the existing named volume. Image
|
||||
upgrades therefore change the execution environment without deleting user
|
||||
files.
|
||||
|
||||
## Networks and deployment
|
||||
|
||||
Production runs as one Unraid Compose Manager project:
|
||||
|
||||
- `public`: Web ingress;
|
||||
- `internal`: private service-to-service traffic;
|
||||
- `egress`: Runtime provider access and Gateway SSH access.
|
||||
|
||||
Only Web publishes NAS port `12004`. Nginx Proxy Manager on the VPS terminates
|
||||
TLS for `agent.k1412.top` and forwards over Tailscale. Images are built for
|
||||
`linux/amd64`, pushed to `docker.k1412.top/wuyang/*` with immutable
|
||||
timestamp-and-commit tags, and deployed by updating only the relevant service.
|
||||
|
||||
The documentation portal is packaged inside the Web image at `/doc/`. It does
|
||||
not add a public service, port, database, or proxy rule.
|
||||
|
||||
## Stable and experimental surfaces
|
||||
|
||||
Stable platform contracts:
|
||||
|
||||
- authenticated Web-to-Runtime request;
|
||||
- signed Runtime/Web-to-Gateway identity;
|
||||
- `ExecutionProvider` workspace semantics;
|
||||
- per-user volume isolation;
|
||||
- run-event persistence;
|
||||
- public model IDs;
|
||||
- workspace file API.
|
||||
|
||||
Expected experiment surfaces:
|
||||
|
||||
- prompt and context policy;
|
||||
- memory selection;
|
||||
- tool catalog and intent routing;
|
||||
- scheduler and parallelism;
|
||||
- delegation;
|
||||
- recovery and evidence rules;
|
||||
- model budgets and routing.
|
||||
|
||||
Version experiment-sensitive behavior in `run.created` so results remain
|
||||
comparable after the implementation changes.
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
# Development and verification
|
||||
|
||||
## Repository layout
|
||||
|
||||
```text
|
||||
agent_platform/
|
||||
runtime/ Agent API, loop, context, model transport, and tools
|
||||
gateway/ Authenticated workspace and file service
|
||||
auth.py Internal service and signed identity verification
|
||||
models.py Public model catalog and server-side budgets
|
||||
store.py Run events, memories, and plans
|
||||
docker/
|
||||
web/ Open WebUI components and reproducible patch set
|
||||
*.Dockerfile Web, Runtime, Gateway, and Workspace images
|
||||
docs/
|
||||
site/ Static source for /doc/
|
||||
deploy/ Production Compose files and SSH override
|
||||
e2e/ Deterministic full-stack verifier and fake provider
|
||||
scripts/ Verification, evaluation, audit, and secret helpers
|
||||
tests/ Unit and real Docker integration tests
|
||||
```
|
||||
|
||||
## Local environment
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
.venv/bin/python -m pip install -e '.[dev]'
|
||||
cp .env.example .env
|
||||
./scripts/init-secrets.sh
|
||||
```
|
||||
|
||||
Keep real provider credentials in a protected local environment or deployment
|
||||
file. Never add them to Git, Docker build arguments, frontend code, test
|
||||
fixtures, or logs.
|
||||
|
||||
Build the user workspace, then start the stack:
|
||||
|
||||
```bash
|
||||
docker compose --profile build-only build workspace-image
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
Open <http://localhost:3000>. New registrations have the `pending` role until
|
||||
approved by the bootstrap administrator.
|
||||
|
||||
## Fast feedback
|
||||
|
||||
```bash
|
||||
.venv/bin/ruff check agent_platform tests e2e
|
||||
.venv/bin/ruff format --check agent_platform tests e2e
|
||||
.venv/bin/pytest
|
||||
```
|
||||
|
||||
Unit tests are deterministic and do not require a model provider.
|
||||
|
||||
## Real Docker integration
|
||||
|
||||
```bash
|
||||
docker build -f docker/workspace.Dockerfile \
|
||||
-t k1412-agent-workspace:test .
|
||||
RUN_DOCKER_INTEGRATION=1 \
|
||||
.venv/bin/pytest tests/test_docker_workspace.py
|
||||
```
|
||||
|
||||
The test creates unique containers, networks, and volumes and removes only
|
||||
those resources in cleanup.
|
||||
|
||||
## Full-stack E2E
|
||||
|
||||
```bash
|
||||
./scripts/verify-e2e.sh
|
||||
```
|
||||
|
||||
The script builds a disposable six-service stack, uses a deterministic model
|
||||
stub, performs authentication and isolation checks, and removes the stack and
|
||||
test volumes on exit.
|
||||
|
||||
## Live Agent evaluation
|
||||
|
||||
```bash
|
||||
set -a
|
||||
source /path/to/protected/provider.env
|
||||
set +a
|
||||
.venv/bin/python scripts/eval-live-work.py --model deepseek-v4-pro
|
||||
```
|
||||
|
||||
Use `--keep-workspace` only when inspecting a failed case; remove that uniquely
|
||||
named evaluation workspace afterward.
|
||||
|
||||
## Image audit
|
||||
|
||||
```bash
|
||||
./scripts/audit-images.sh
|
||||
```
|
||||
|
||||
The audit requires consistent Python environments and no fixable
|
||||
High/Critical vulnerabilities in the finished images. Web also receives a
|
||||
Python dependency audit.
|
||||
|
||||
## Documentation portal
|
||||
|
||||
`docs/site/` is dependency-free static HTML, CSS, JavaScript, and JSON. It is
|
||||
copied into `/app/build/doc` by `docker/web.Dockerfile` after Open WebUI's
|
||||
frontend build completes.
|
||||
|
||||
Validate it locally with:
|
||||
|
||||
```bash
|
||||
python3 -m http.server 4173 --directory docs/site
|
||||
```
|
||||
|
||||
The production path is `/doc/`; all internal assets therefore use relative
|
||||
URLs. Keep the Markdown documents and portal content aligned in the same
|
||||
commit. Add experiment cards through `docs/site/experiments.json`.
|
||||
|
||||
## Change checklist
|
||||
|
||||
Before pushing:
|
||||
|
||||
1. keep unrelated working-tree changes untouched;
|
||||
2. update architecture or behavior documentation;
|
||||
3. add deterministic tests for policy changes;
|
||||
4. run unit and formatting checks;
|
||||
5. run Docker integration for workspace/Gateway changes;
|
||||
6. run E2E for public model, auth, loop, or file-delivery changes;
|
||||
7. audit every rebuilt image;
|
||||
8. use immutable production image tags;
|
||||
9. verify public health and one representative user flow;
|
||||
10. retain the previous image and deployment backup until verification passes.
|
||||
@@ -0,0 +1,133 @@
|
||||
# Agent experiment system
|
||||
|
||||
## Goal
|
||||
|
||||
The project exists to make Agent-loop iteration cheap, observable, and
|
||||
reversible. An experiment should change one behavioral hypothesis while
|
||||
holding authentication, workspace isolation, and delivery infrastructure
|
||||
constant.
|
||||
|
||||
The public portal at <https://agent.k1412.top/doc/#experiments> contains a
|
||||
curated experiment board. This Markdown document defines the durable process;
|
||||
the portal catalog is a presentation layer.
|
||||
|
||||
## Experiment unit
|
||||
|
||||
Every experiment should define:
|
||||
|
||||
1. **Question** — the behavior we want to improve.
|
||||
2. **Hypothesis** — the concrete loop change and expected direction.
|
||||
3. **Variant identifier** — a stable string recorded in `run.created`.
|
||||
4. **Task set** — fixed prompts, starting workspace fixtures, and model tier.
|
||||
5. **Metrics** — success, quality, latency, model/tool usage, and regressions.
|
||||
6. **Safety constraints** — behavior that must not worsen.
|
||||
7. **Decision rule** — promote, iterate, or reject.
|
||||
8. **Artifact** — code commit, configuration, raw event export, and report.
|
||||
|
||||
Do not compare variants from different task inputs or silently change the
|
||||
model, prompt, context budget, or workspace fixture.
|
||||
|
||||
## Recommended metrics
|
||||
|
||||
Primary:
|
||||
|
||||
- task success under explicit evidence checks;
|
||||
- verified-deliverable rate;
|
||||
- unresolved tool-failure rate;
|
||||
- human or rubric quality score.
|
||||
|
||||
Efficiency:
|
||||
|
||||
- end-to-end latency;
|
||||
- model calls and iterations;
|
||||
- prompt/completion tokens when available;
|
||||
- tool-call count;
|
||||
- duplicated or policy-blocked calls;
|
||||
- child-Agent count and concurrency;
|
||||
- estimated provider and electricity cost.
|
||||
|
||||
Reliability and safety:
|
||||
|
||||
- incomplete checkpoints correctly rejected;
|
||||
- false-success rate;
|
||||
- workspace escape or cross-user access failures;
|
||||
- non-zero command exits incorrectly recorded as success;
|
||||
- identity/authentication failures;
|
||||
- Runtime or workspace restart recovery.
|
||||
|
||||
## Evaluation layers
|
||||
|
||||
### Unit and policy tests
|
||||
|
||||
Fast deterministic tests cover parsing, tool normalization, evidence gates,
|
||||
authentication, context selection, event persistence, and provider response
|
||||
normalization.
|
||||
|
||||
### Real Docker integration
|
||||
|
||||
The integration test creates two disposable users and proves:
|
||||
|
||||
- separate containers, networks, and volumes;
|
||||
- workspace path confinement;
|
||||
- file browse/download/archive behavior;
|
||||
- read-only root and dropped capabilities;
|
||||
- persistent Python virtual environments;
|
||||
- foreground and background `pipefail` exit codes.
|
||||
|
||||
### Disposable full-stack E2E
|
||||
|
||||
The E2E stack uses a deterministic fake model provider and exercises:
|
||||
|
||||
- registration and admin approval;
|
||||
- the exact four-model public catalog;
|
||||
- the custom Agent loop;
|
||||
- evidence-backed file generation;
|
||||
- file delivery;
|
||||
- per-user isolation.
|
||||
|
||||
### Live-model evaluation
|
||||
|
||||
`scripts/eval-live-work.py` runs a real model against a unique disposable
|
||||
workspace and records latency, token usage, events, tool counts, and output
|
||||
files. Live evaluations complement deterministic tests; they do not replace
|
||||
them.
|
||||
|
||||
### Production smoke test
|
||||
|
||||
After deployment, use a low-impact authenticated task to confirm public Web,
|
||||
Runtime, Gateway, the remote workspace host, and file retrieval. Remove only
|
||||
the smoke artifact after verification.
|
||||
|
||||
## Current baselines
|
||||
|
||||
| ID | Area | Status | Result |
|
||||
| --- | --- | --- | --- |
|
||||
| `loop-v3-evidence` | Completion policy | Production baseline | Artifacts require mutation followed by verification; reports and benchmarks require stronger evidence. |
|
||||
| `safe-parallel-v1` | Scheduler | Production baseline | Consecutive read-only calls and read-only delegates run concurrently; mutations remain serialized. |
|
||||
| `recent-visible-v1` | Context | Production baseline | Keep recent visible messages under a per-model character budget and attach up to eight memories. |
|
||||
| `workspace-python-v1` | Execution | Validated | Persistent `.venv`, persistent user caches, 900-second tool ceiling, and true pipeline exits. |
|
||||
| `fresh-gateway-identity-v1` | Authentication | Validated | Runtime re-signs verified identity for each tool request so long runs survive the original token expiry. |
|
||||
|
||||
## Initial backlog
|
||||
|
||||
1. Semantic or hybrid memory retrieval with conflict and expiry policy.
|
||||
2. Structured old-context summarization with replay comparison.
|
||||
3. Dependency-aware tool DAG scheduling rather than consecutive safe groups.
|
||||
4. Child-Agent result contracts and budget allocation.
|
||||
5. Experiment assignment stored per run and an aggregate comparison API.
|
||||
6. Cost accounting across local electricity and paid provider tokens.
|
||||
7. Workspace quotas, egress policy, abuse monitoring, and backup drills.
|
||||
|
||||
## Adding an experiment
|
||||
|
||||
1. Add the hypothesis and metrics to this document or a dedicated
|
||||
`docs/experiments/<id>.md` file.
|
||||
2. Add the experiment to `docs/site/experiments.json` for the public board.
|
||||
3. Add or update the relevant strategy/scheduler/context identifier in
|
||||
`run.created`.
|
||||
4. Add deterministic tests before a live run.
|
||||
5. Run the standard verification and capture a report.
|
||||
6. Promote with an immutable image tag; retain the previous tag for rollback.
|
||||
|
||||
Never put provider keys, private event payloads, user identifiers, prompts from
|
||||
real users, or internal credentials in an experiment artifact.
|
||||
@@ -3,6 +3,7 @@
|
||||
## Production layout
|
||||
|
||||
- Public URL: `https://agent.k1412.top`
|
||||
- Public documentation: `https://agent.k1412.top/doc/`
|
||||
- NAS project: `/boot/config/plugins/compose.manager/projects/k1412-agent`
|
||||
- Public host port: `12004`
|
||||
- Execution provider: `ssh-docker`
|
||||
@@ -47,6 +48,11 @@ Compose file, image, repository, or log.
|
||||
The SSH override removes `/var/run/docker.sock` from Gateway and mounts the
|
||||
dedicated SSH directory read-only at `/root/.ssh`.
|
||||
|
||||
The documentation portal is copied into the existing Web image at
|
||||
`/app/build/doc`. It uses the same host port and proxy route as Open WebUI, so
|
||||
it does not require another Compose project, NAS port, DNS record, or Nginx
|
||||
Proxy Manager host.
|
||||
|
||||
The Workspace image keeps the user home, package caches, and Python user base
|
||||
under `/workspace/.agent`; the conventional project virtual environment is
|
||||
`/workspace/.venv`. Updating `WORKSPACE_IMAGE` to a new immutable tag causes
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
# Project history and decisions
|
||||
|
||||
This record summarizes the rebuild that began on 2026-07-26. Git remains the
|
||||
source of truth for exact changes; this document captures product intent and
|
||||
architecture decisions that are otherwise difficult to reconstruct from
|
||||
individual commits.
|
||||
|
||||
## 1. Clean-slate web Agent
|
||||
|
||||
The existing business/data-specific application was declared a new project
|
||||
with no backward-compatibility requirement. Business skills, domain workflows,
|
||||
and user-configurable provider settings were removed from scope. The retained
|
||||
core requirement was general coding-Agent capability with an independently
|
||||
evolvable loop.
|
||||
|
||||
Decision:
|
||||
|
||||
- build one general multi-user Web Agent;
|
||||
- preserve coding, shell, file, Git, process, planning, memory, and delegation
|
||||
capabilities;
|
||||
- keep infrastructure and product shell separate from Agent intelligence.
|
||||
|
||||
## 2. Open WebUI as product shell
|
||||
|
||||
Instead of maintaining a second full account/chat frontend, Open WebUI v0.9.6
|
||||
was pinned and lightly patched. It supplies registration, login, RBAC,
|
||||
administrator approval, conversation history, and familiar chat interaction.
|
||||
|
||||
K1412 kept ownership of the Agent loop, provider routing, memory, tools,
|
||||
scheduling, events, and workspace execution. This reduced the cost of Agent
|
||||
experiments without making the loop dependent on Open WebUI internals.
|
||||
|
||||
## 3. One Agent path, not Chat versus Work
|
||||
|
||||
An early design considered a switch between Open WebUI's native Chat loop and
|
||||
the K1412 Work loop. The product was simplified to one Agent path because:
|
||||
|
||||
- users should not need to understand two orchestration engines;
|
||||
- conversation continuation between modes creates ambiguous state;
|
||||
- two loops double frontend states and verification behavior;
|
||||
- the custom loop is the main research asset.
|
||||
|
||||
The remaining interface is an Agent-first chat with server-owned model
|
||||
selection.
|
||||
|
||||
## 4. Model and thinking semantics
|
||||
|
||||
The original “light / medium / high reasoning” labels conflated different
|
||||
models with adjustable effort. The UI and backend now distinguish model
|
||||
identity from thinking capability:
|
||||
|
||||
- Luna, Terra, and Sol are separate local K1412/Ollama models;
|
||||
- each exposes thinking as enabled but without adjustable effort levels;
|
||||
- DeepSeek V4 Pro is the cloud extreme tier with maximum reasoning effort.
|
||||
|
||||
Provider model IDs, URLs, credentials, and tuning remain server-side.
|
||||
|
||||
## 5. Multi-user remote workspaces
|
||||
|
||||
Each user received a dedicated Docker container, network, and persistent volume
|
||||
derived from a hashed immutable user ID. Execution moved from the NAS to the
|
||||
physical `home-node-itx` through SSH Docker.
|
||||
|
||||
The physical node was prepared with:
|
||||
|
||||
- an ext4 500 GB data disk mounted at `/srv/k1412-data`;
|
||||
- Docker root under `/srv/k1412-data/docker`;
|
||||
- strict SSH host verification;
|
||||
- no application/database secrets.
|
||||
|
||||
The local and SSH execution providers retain one interface so the host can be
|
||||
replaced without changing Agent behavior.
|
||||
|
||||
## 6. File delivery and focused UI
|
||||
|
||||
The frontend was simplified around the Agent:
|
||||
|
||||
- K1412 product title and assets;
|
||||
- a compact model selector with separate thinking status;
|
||||
- no exposed provider/tool/system-prompt settings;
|
||||
- an authenticated workspace file browser;
|
||||
- single-file download and streamed directory archive.
|
||||
|
||||
Open WebUI attribution and license requirements remain documented.
|
||||
|
||||
## 7. Loop hardening through failed-task analysis
|
||||
|
||||
Real sorting-script/report tasks exposed model weaknesses and platform bugs.
|
||||
The loop was progressively hardened to:
|
||||
|
||||
- require actual files rather than textual claims;
|
||||
- require executable source separately from reports;
|
||||
- run the source before writing a report;
|
||||
- require measured benchmark values;
|
||||
- reject invalid Python and escaped-layout corruption;
|
||||
- recover from failed verification;
|
||||
- prevent unchanged retry loops and duplicate batches;
|
||||
- preserve failures even when output is piped through another command;
|
||||
- bound iteration, tool-batch, model-output, and retry budgets.
|
||||
|
||||
These constraints are not assumed permanently optimal. They are the current
|
||||
baseline and should be removed or changed only through measured experiments.
|
||||
|
||||
## 8. Python environment and long-run reliability
|
||||
|
||||
Production debugging found three platform problems:
|
||||
|
||||
1. the container root was read-only while `pip` defaulted to `/home/agent`;
|
||||
2. `/tmp` was `noexec`;
|
||||
3. shell pipelines returned the last command's status, hiding failed installs.
|
||||
|
||||
The fix moved home, caches, user packages, and virtual environments to the
|
||||
persistent workspace, enabled Bash `pipefail`, extended tool timeouts to 900
|
||||
seconds, and taught the Agent the supported `.venv` workflow.
|
||||
|
||||
The same investigation found that a five-minute identity token was reused for
|
||||
every tool in a long run. Runtime now signs a fresh short-lived identity for
|
||||
each Gateway call after the original request identity has been verified.
|
||||
|
||||
Production validation created a real `.venv`, installed and imported
|
||||
`psutil 7.2.2`, downloaded the generated proof file through the Web API, and
|
||||
then removed the temporary proof file.
|
||||
|
||||
## 9. Documentation and experiment portal
|
||||
|
||||
The repository documentation was reorganized around architecture, Agent
|
||||
implementation, security, operations, history, development, and experiments.
|
||||
The curated public portal is shipped inside the existing Web image at
|
||||
`/doc/`, avoiding a second service or proxy rule.
|
||||
|
||||
## Current direction
|
||||
|
||||
The platform is now suitable for controlled Agent-loop experimentation. The
|
||||
next work should prioritize evaluation data, context/memory experiments,
|
||||
scheduler design, delegation contracts, cost accounting, and hardening for
|
||||
hostile multi-tenant use rather than adding business-specific workflows.
|
||||
@@ -0,0 +1,265 @@
|
||||
const flows = {
|
||||
agent: {
|
||||
kicker: 'AGENT REQUEST / 7 HOPS',
|
||||
description:
|
||||
'浏览器的已登录请求由 Web 转换成兼容 OpenAI 的流式调用;Runtime 独立完成上下文构建、模型调用、工具循环和证据校验。',
|
||||
nodes: ['browser', 'web', 'runtime', 'provider', 'gateway', 'workspace', 'store']
|
||||
},
|
||||
identity: {
|
||||
kicker: 'IDENTITY / SHORT-LIVED & SERVER-SIDE',
|
||||
description:
|
||||
'Web 先验证登录用户并签发短期身份;Runtime 验证一次后,在每次 Gateway 工具调用前重新签发,避免长任务复用过期令牌。',
|
||||
nodes: ['browser', 'web', 'runtime', 'gateway', 'workspace']
|
||||
},
|
||||
tool: {
|
||||
kicker: 'TOOL EXECUTION / POLICY BEFORE DOCKER',
|
||||
description:
|
||||
'Runtime 校验并调度工具,Gateway 再执行身份、路径和资源策略,最后才通过 SSH Docker 进入该用户唯一的工作区。',
|
||||
nodes: ['runtime', 'gateway', 'workspace', 'store']
|
||||
},
|
||||
file: {
|
||||
kicker: 'FILE DELIVERY / AUTHENTICATED STREAM',
|
||||
description:
|
||||
'用户在工作区抽屉发起浏览或下载;Web 验证会话后请求 Gateway,文件或归档以流式响应返回,浏览器从不接触内部服务密钥。',
|
||||
nodes: ['browser', 'web', 'gateway', 'workspace']
|
||||
}
|
||||
};
|
||||
|
||||
const stages = {
|
||||
context: {
|
||||
kicker: 'CONTEXT / recent-visible-v1',
|
||||
title: '把有限上下文留给真正影响下一步的内容',
|
||||
description:
|
||||
'移除旧的工具详情渲染,按模型预算保留最新可见消息,再注入最多 8 条持久记忆。上下文策略和 Agent Loop 分别版本化。',
|
||||
points: [
|
||||
'去掉历史消息中的工具 UI 标记',
|
||||
'最近消息优先,按字符预算截断',
|
||||
'记忆只作为补充上下文,不直接取得执行权限'
|
||||
]
|
||||
},
|
||||
model: {
|
||||
kicker: 'MODEL / SERVER-SIDE CATALOG',
|
||||
title: '模型提出下一步,平台控制它能看到和能花费什么',
|
||||
description:
|
||||
'Runtime 根据公开模型 ID 选择固定 provider、上下文预算、输出预算和循环上限。用户不能从前端注入密钥或任意模型参数。',
|
||||
points: ['支持流式内容与工具调用', '模型和推理强度明确标注', 'provider 差异在传输层统一']
|
||||
},
|
||||
validate: {
|
||||
kicker: 'VALIDATE / NORMALIZE BEFORE TRUST',
|
||||
title: '先把模型输出变成可约束的数据,再决定是否执行',
|
||||
description:
|
||||
'工具名称、参数、批次数量和权限都在执行前检查。一次模型响应最多接受 8 个工具调用,未知或畸形调用会成为可见错误。',
|
||||
points: ['JSON 参数规范化', '工具白名单与参数校验', '重复无进展调用守卫']
|
||||
},
|
||||
schedule: {
|
||||
kicker: 'SCHEDULER / safe-parallel-v1',
|
||||
title: '读取可以加速,写入必须保持可预测',
|
||||
description:
|
||||
'连续且标记为 parallel_safe 的工具并发执行;任何文件写入、命令或状态变更都会形成串行边界,结果按请求顺序返回模型。',
|
||||
points: ['只读调用成组并发', '变更操作严格串行', '批次结果仍保持稳定顺序']
|
||||
},
|
||||
execute: {
|
||||
kicker: 'EXECUTE / TOOLS + BOUNDED DELEGATION',
|
||||
title: '所有能力都通过可记录、可验证的工具边界发生',
|
||||
description:
|
||||
'文件、命令、Git、计划和记忆都有结构化工具。Workspace 工具经 Gateway 进入用户容器;只读子任务可以受限委派。',
|
||||
points: ['工作区工具与状态工具分离', '每次调用记录开始和结果事件', '子 Agent 不得再次委派']
|
||||
},
|
||||
evidence: {
|
||||
kicker: 'EVIDENCE / COMPLETION IS A POLICY',
|
||||
title: '“完成”不是一句自然语言,而是一组已经发生的事实',
|
||||
description:
|
||||
'如果任务要求生成文件、修改代码或给出测量报告,循环必须看到相应的写入、验证和精确结果。证据不足时会继续循环或明确失败。',
|
||||
points: ['变更后必须有后续验证', '失败命令必须修复并重跑', '报告必须晚于来源或实验结果']
|
||||
}
|
||||
};
|
||||
|
||||
const statusLabels = {
|
||||
baseline: '当前基线',
|
||||
validated: '已验证',
|
||||
backlog: '待实验'
|
||||
};
|
||||
|
||||
let experimentData = [];
|
||||
let activeExperimentFilter = 'all';
|
||||
|
||||
function activateFlow(flowName) {
|
||||
const flow = flows[flowName];
|
||||
if (!flow) return;
|
||||
|
||||
document.querySelectorAll('.flow-tab').forEach((button) => {
|
||||
const active = button.dataset.flow === flowName;
|
||||
button.classList.toggle('is-active', active);
|
||||
button.setAttribute('aria-selected', String(active));
|
||||
});
|
||||
|
||||
document.querySelectorAll('.system-node').forEach((node) => {
|
||||
node.classList.toggle('is-flow-active', flow.nodes.includes(node.dataset.node));
|
||||
});
|
||||
|
||||
document.querySelector('.system-map')?.classList.add('has-selection');
|
||||
document.querySelector('#flow-kicker').textContent = flow.kicker;
|
||||
document.querySelector('#flow-description').textContent = flow.description;
|
||||
}
|
||||
|
||||
function activateStage(stageName) {
|
||||
const stage = stages[stageName];
|
||||
if (!stage) return;
|
||||
|
||||
document.querySelectorAll('.loop-stage').forEach((button) => {
|
||||
const active = button.dataset.stage === stageName;
|
||||
button.classList.toggle('is-active', active);
|
||||
button.setAttribute('aria-selected', String(active));
|
||||
});
|
||||
|
||||
document.querySelector('#stage-kicker').textContent = stage.kicker;
|
||||
document.querySelector('#stage-title').textContent = stage.title;
|
||||
document.querySelector('#stage-description').textContent = stage.description;
|
||||
|
||||
const list = document.querySelector('#stage-points');
|
||||
list.replaceChildren(
|
||||
...stage.points.map((point) => {
|
||||
const item = document.createElement('li');
|
||||
item.textContent = point;
|
||||
return item;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function experimentCard(experiment) {
|
||||
const article = document.createElement('article');
|
||||
article.className = 'experiment-card';
|
||||
|
||||
const meta = document.createElement('div');
|
||||
meta.className = 'experiment-meta';
|
||||
|
||||
const id = document.createElement('span');
|
||||
id.textContent = experiment.id;
|
||||
|
||||
const badge = document.createElement('span');
|
||||
badge.className = `status-badge status-${experiment.status}`;
|
||||
badge.textContent = statusLabels[experiment.status];
|
||||
meta.append(id, badge);
|
||||
|
||||
const title = document.createElement('h3');
|
||||
title.textContent = experiment.title;
|
||||
|
||||
const summary = document.createElement('p');
|
||||
summary.textContent = experiment.summary;
|
||||
|
||||
const footer = document.createElement('div');
|
||||
footer.className = 'experiment-footer';
|
||||
[experiment.area, experiment.version, ...(experiment.metrics || [])].filter(Boolean).forEach((text) => {
|
||||
const tag = document.createElement('span');
|
||||
tag.textContent = text;
|
||||
footer.append(tag);
|
||||
});
|
||||
|
||||
article.append(meta, title, summary, footer);
|
||||
return article;
|
||||
}
|
||||
|
||||
function renderExperiments() {
|
||||
const query = document.querySelector('#experiment-search').value.trim().toLocaleLowerCase('zh-CN');
|
||||
const filtered = experimentData.filter((experiment) => {
|
||||
const statusMatches =
|
||||
activeExperimentFilter === 'all' || experiment.status === activeExperimentFilter;
|
||||
const haystack = [
|
||||
experiment.id,
|
||||
experiment.title,
|
||||
experiment.summary,
|
||||
experiment.area,
|
||||
experiment.version,
|
||||
...(experiment.metrics || [])
|
||||
]
|
||||
.join(' ')
|
||||
.toLocaleLowerCase('zh-CN');
|
||||
return statusMatches && (!query || haystack.includes(query));
|
||||
});
|
||||
|
||||
const grid = document.querySelector('#experiment-grid');
|
||||
if (filtered.length === 0) {
|
||||
const empty = document.createElement('article');
|
||||
empty.className = 'experiment-empty';
|
||||
empty.textContent = '没有匹配的实验记录。';
|
||||
grid.replaceChildren(empty);
|
||||
} else {
|
||||
grid.replaceChildren(...filtered.map(experimentCard));
|
||||
}
|
||||
|
||||
document.querySelector('#experiment-count').textContent =
|
||||
`${String(filtered.length).padStart(2, '0')} / ${String(experimentData.length).padStart(2, '0')} RECORDS`;
|
||||
}
|
||||
|
||||
async function loadExperiments() {
|
||||
const grid = document.querySelector('#experiment-grid');
|
||||
try {
|
||||
const response = await fetch('./experiments.json', { cache: 'no-cache' });
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
experimentData = await response.json();
|
||||
renderExperiments();
|
||||
} catch (error) {
|
||||
const failure = document.createElement('article');
|
||||
failure.className = 'experiment-empty';
|
||||
failure.textContent = '实验台账暂时无法读取,请查看仓库中的 docs/experiments.md。';
|
||||
grid.replaceChildren(failure);
|
||||
document.querySelector('#experiment-count').textContent = 'DATA UNAVAILABLE';
|
||||
}
|
||||
}
|
||||
|
||||
function setActiveNavigation(sectionId) {
|
||||
document.querySelectorAll('.nav-link').forEach((link) => {
|
||||
link.classList.toggle('is-active', link.getAttribute('href') === `#${sectionId}`);
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelectorAll('.flow-tab').forEach((button) => {
|
||||
button.addEventListener('click', () => activateFlow(button.dataset.flow));
|
||||
});
|
||||
|
||||
document.querySelectorAll('.loop-stage').forEach((button) => {
|
||||
button.addEventListener('click', () => activateStage(button.dataset.stage));
|
||||
});
|
||||
|
||||
document.querySelectorAll('.filter-button').forEach((button) => {
|
||||
button.addEventListener('click', () => {
|
||||
activeExperimentFilter = button.dataset.filter;
|
||||
document
|
||||
.querySelectorAll('.filter-button')
|
||||
.forEach((candidate) => candidate.classList.toggle('is-active', candidate === button));
|
||||
renderExperiments();
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelector('#experiment-search').addEventListener('input', renderExperiments);
|
||||
|
||||
const toggle = document.querySelector('.nav-toggle');
|
||||
const sidebar = document.querySelector('.sidebar');
|
||||
toggle.addEventListener('click', () => {
|
||||
const isOpen = sidebar.classList.toggle('is-open');
|
||||
toggle.setAttribute('aria-expanded', String(isOpen));
|
||||
});
|
||||
|
||||
document.querySelectorAll('.nav-link').forEach((link) => {
|
||||
link.addEventListener('click', () => {
|
||||
sidebar.classList.remove('is-open');
|
||||
toggle.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
});
|
||||
|
||||
if ('IntersectionObserver' in window) {
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
const visible = entries
|
||||
.filter((entry) => entry.isIntersecting)
|
||||
.sort((a, b) => b.intersectionRatio - a.intersectionRatio);
|
||||
if (visible[0]) setActiveNavigation(visible[0].target.id);
|
||||
},
|
||||
{ rootMargin: '-20% 0px -62% 0px', threshold: [0.05, 0.3] }
|
||||
);
|
||||
document.querySelectorAll('main > section[id]').forEach((section) => observer.observe(section));
|
||||
}
|
||||
|
||||
activateFlow('agent');
|
||||
activateStage('context');
|
||||
loadExperiments();
|
||||
@@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"id": "BASE-001",
|
||||
"title": "统一 Agent 路径",
|
||||
"summary": "删除 Chat / Work 双模式,所有对话通过同一套可观测 Agent Loop;减少前端状态和后端分叉。",
|
||||
"area": "product",
|
||||
"status": "validated",
|
||||
"version": "agent-loop-v3",
|
||||
"metrics": ["维护面", "交互一致性"]
|
||||
},
|
||||
{
|
||||
"id": "BASE-002",
|
||||
"title": "安全读取并行,变更串行",
|
||||
"summary": "连续 parallel_safe 调用并发执行,写文件、命令和状态变更维持模型给出的顺序。",
|
||||
"area": "scheduler",
|
||||
"status": "baseline",
|
||||
"version": "safe-parallel-v1",
|
||||
"metrics": ["wall time", "determinism"]
|
||||
},
|
||||
{
|
||||
"id": "BASE-003",
|
||||
"title": "最近可见上下文",
|
||||
"summary": "清除旧工具详情,按模型字符预算保留最近消息,并注入最多 8 条持久记忆。",
|
||||
"area": "context",
|
||||
"status": "baseline",
|
||||
"version": "recent-visible-v1",
|
||||
"metrics": ["token proxy", "task success"]
|
||||
},
|
||||
{
|
||||
"id": "BASE-004",
|
||||
"title": "证据驱动的完成判定",
|
||||
"summary": "文件、代码和报告任务必须出现写入与后续验证;未解决的命令失败会阻止虚假完成。",
|
||||
"area": "reliability",
|
||||
"status": "validated",
|
||||
"version": "evidence-gate-v1",
|
||||
"metrics": ["false completion", "artifact validity"]
|
||||
},
|
||||
{
|
||||
"id": "BASE-005",
|
||||
"title": "持久 Python 工具链",
|
||||
"summary": "用户依赖安装到 /workspace/.venv;镜像升级保留环境,pipefail 防止安装失败被管道尾部掩盖。",
|
||||
"area": "workspace",
|
||||
"status": "validated",
|
||||
"version": "workspace-python-v2",
|
||||
"metrics": ["install success", "restart survival"]
|
||||
},
|
||||
{
|
||||
"id": "EXP-006",
|
||||
"title": "基于相关性的记忆召回",
|
||||
"summary": "比较固定最近记忆、关键词召回和向量召回对长期偏好遵循、上下文成本与错误注入的影响。",
|
||||
"area": "memory",
|
||||
"status": "backlog",
|
||||
"version": "proposal",
|
||||
"metrics": ["recall@k", "task success", "context cost"]
|
||||
},
|
||||
{
|
||||
"id": "EXP-007",
|
||||
"title": "依赖感知工具调度",
|
||||
"summary": "从显式工具属性推进到调用间读写集分析,评估是否能扩大安全并行范围。",
|
||||
"area": "scheduler",
|
||||
"status": "backlog",
|
||||
"version": "proposal",
|
||||
"metrics": ["wall time", "race failures", "parallel ratio"]
|
||||
},
|
||||
{
|
||||
"id": "EXP-008",
|
||||
"title": "自适应模型路由",
|
||||
"summary": "以任务复杂度和中途失败信号决定 Luna、Terra、Sol 或 DeepSeek,而不是让一次选择锁定整个任务。",
|
||||
"area": "model-routing",
|
||||
"status": "backlog",
|
||||
"version": "proposal",
|
||||
"metrics": ["task success", "latency", "API cost"]
|
||||
},
|
||||
{
|
||||
"id": "EXP-009",
|
||||
"title": "受限多 Agent 拓扑",
|
||||
"summary": "比较单循环、只读并行委派和角色化子 Agent,在复杂代码任务中的收益与上下文整合成本。",
|
||||
"area": "delegation",
|
||||
"status": "backlog",
|
||||
"version": "proposal",
|
||||
"metrics": ["task success", "wall time", "tool calls"]
|
||||
},
|
||||
{
|
||||
"id": "EXP-010",
|
||||
"title": "上下文压缩与可逆摘要",
|
||||
"summary": "在最近消息预算之外保存结构化任务状态,并允许模型按需取回原始证据,减少长任务遗忘。",
|
||||
"area": "context",
|
||||
"status": "backlog",
|
||||
"version": "proposal",
|
||||
"metrics": ["long-horizon success", "context cost", "retrieval count"]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,570 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#f2f0e9" />
|
||||
<title>K1412 Agent · 架构、实现与实验</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="K1412 多用户 Web Agent 的架构设计、Agent Loop 实现、隔离模型和实验记录。"
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="K1412 Agent" />
|
||||
<meta property="og:title" content="K1412 Agent · Architecture & Experiments" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="A multi-user Web Agent built as an evolvable system for context, tools, parallelism, memory and delegation."
|
||||
/>
|
||||
<meta property="og:url" content="https://agent.k1412.top/doc/" />
|
||||
<meta property="og:image" content="https://agent.k1412.top/doc/og.png" />
|
||||
<link rel="icon" href="../static/favicon.svg" type="image/svg+xml" />
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
<script>
|
||||
document.documentElement.classList.add('js');
|
||||
</script>
|
||||
<script src="./app.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<a class="skip-link" href="#main-content">跳到正文</a>
|
||||
|
||||
<header class="topbar">
|
||||
<a class="brand" href="#overview" aria-label="K1412 Agent 文档首页">
|
||||
<span class="brand-mark" aria-hidden="true">K</span>
|
||||
<span>
|
||||
<strong>K1412 Agent</strong>
|
||||
<small>Architecture / Lab Notes</small>
|
||||
</span>
|
||||
</a>
|
||||
<div class="topbar-actions">
|
||||
<span class="system-status"><i></i> 当前架构 · 2026.07</span>
|
||||
<a class="button button-quiet hide-mobile" href="https://git.k1412.top/wuyang/zk-data-agent">
|
||||
查看源码
|
||||
</a>
|
||||
<a class="button button-primary" href="/">进入 Agent <span aria-hidden="true">↗</span></a>
|
||||
<button
|
||||
class="nav-toggle"
|
||||
type="button"
|
||||
aria-label="打开文档目录"
|
||||
aria-expanded="false"
|
||||
aria-controls="side-navigation"
|
||||
>
|
||||
<span></span><span></span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="page-shell">
|
||||
<aside class="sidebar" id="side-navigation">
|
||||
<nav aria-label="文档目录">
|
||||
<p class="nav-label">系统</p>
|
||||
<a class="nav-link is-active" href="#overview"><span>01</span>概览</a>
|
||||
<a class="nav-link" href="#architecture"><span>02</span>架构边界</a>
|
||||
<a class="nav-link" href="#agent-loop"><span>03</span>Agent Loop</a>
|
||||
<a class="nav-link" href="#workspace"><span>04</span>执行空间</a>
|
||||
<a class="nav-link" href="#models"><span>05</span>模型与强度</a>
|
||||
<p class="nav-label">演进</p>
|
||||
<a class="nav-link" href="#experiments"><span>06</span>实验记录</a>
|
||||
<a class="nav-link" href="#operations"><span>07</span>部署与观测</a>
|
||||
<a class="nav-link" href="#timeline"><span>08</span>项目历程</a>
|
||||
<a class="nav-link" href="#repository"><span>09</span>仓库文档</a>
|
||||
</nav>
|
||||
<div class="sidebar-note">
|
||||
<span>核心原则</span>
|
||||
<p>稳定的平台外壳,快速演进的 Agent 核心。</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main id="main-content">
|
||||
<section class="hero section" id="overview">
|
||||
<div class="eyebrow"><span>ONE AGENT PATH</span> / MULTI-USER / SELF-HOSTED</div>
|
||||
<h1>一套可以被持续<br />实验的 Web Agent</h1>
|
||||
<p class="hero-copy">
|
||||
K1412 Agent 把账户、界面和执行隔离做成稳定平台,把上下文、工具调度、并行、多 Agent、
|
||||
记忆和完成判定留在我们自己的 Agent Loop 中。这里既是系统说明,也是后续实验的公开台账。
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a class="button button-dark" href="#architecture">理解架构 <span aria-hidden="true">↓</span></a>
|
||||
<a class="text-link" href="#experiments">查看实验记录 <span aria-hidden="true">→</span></a>
|
||||
</div>
|
||||
|
||||
<div class="metric-strip" aria-label="当前系统摘要">
|
||||
<div>
|
||||
<strong>01</strong>
|
||||
<span>统一 Agent 路径</span>
|
||||
<small>没有 Chat / Work 分叉</small>
|
||||
</div>
|
||||
<div>
|
||||
<strong>04</strong>
|
||||
<span>可选模型</span>
|
||||
<small>模型与推理强度分离</small>
|
||||
</div>
|
||||
<div>
|
||||
<strong>1 : 1</strong>
|
||||
<span>用户执行空间</span>
|
||||
<small>容器、网络与持久卷</small>
|
||||
</div>
|
||||
<div>
|
||||
<strong>SSE</strong>
|
||||
<span>运行事件流</span>
|
||||
<small>模型、工具与完成证据</small>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section architecture-section" id="architecture">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<span class="section-index">02 / ARCHITECTURE</span>
|
||||
<h2>稳定外壳与<br />实验核心解耦</h2>
|
||||
</div>
|
||||
<p>
|
||||
点击一条链路,观察一次请求如何穿过系统。公开入口只有 Web;模型密钥、Docker
|
||||
权限和用户执行环境始终留在服务端。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="architecture-lab">
|
||||
<div class="flow-tabs" role="tablist" aria-label="架构链路">
|
||||
<button class="flow-tab is-active" type="button" role="tab" data-flow="agent">
|
||||
Agent 请求
|
||||
</button>
|
||||
<button class="flow-tab" type="button" role="tab" data-flow="identity">身份链路</button>
|
||||
<button class="flow-tab" type="button" role="tab" data-flow="tool">工具执行</button>
|
||||
<button class="flow-tab" type="button" role="tab" data-flow="file">文件交付</button>
|
||||
</div>
|
||||
|
||||
<div class="system-map" aria-label="K1412 Agent 系统架构图">
|
||||
<div class="map-lane map-public">
|
||||
<span class="lane-label">PUBLIC EDGE</span>
|
||||
<article class="system-node" data-node="browser">
|
||||
<small>01 / CLIENT</small>
|
||||
<strong>Browser</strong>
|
||||
<span>登录、会话、文件下载</span>
|
||||
</article>
|
||||
<span class="map-arrow" aria-hidden="true">→</span>
|
||||
<article class="system-node node-web" data-node="web">
|
||||
<small>02 / STABLE SHELL</small>
|
||||
<strong>Open WebUI</strong>
|
||||
<span>Auth · RBAC · History · UI</span>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="map-lane map-core">
|
||||
<span class="lane-label">PRIVATE APPLICATION NETWORK</span>
|
||||
<article class="system-node node-runtime" data-node="runtime">
|
||||
<small>03 / EXPERIMENT CORE</small>
|
||||
<strong>Agent Runtime</strong>
|
||||
<span>Context · Loop · Tools · Memory</span>
|
||||
</article>
|
||||
<span class="map-arrow" aria-hidden="true">→</span>
|
||||
<article class="system-node" data-node="provider">
|
||||
<small>04 / INFERENCE</small>
|
||||
<strong>Model Provider</strong>
|
||||
<span>K1412 API · DeepSeek</span>
|
||||
</article>
|
||||
<article class="system-node" data-node="gateway">
|
||||
<small>05 / POLICY GATE</small>
|
||||
<strong>Workspace Gateway</strong>
|
||||
<span>Identity · Path · Docker lifecycle</span>
|
||||
</article>
|
||||
<article class="system-node node-store" data-node="store">
|
||||
<small>STATE</small>
|
||||
<strong>PostgreSQL + Redis</strong>
|
||||
<span>Chats · Events · Plans · Memory</span>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="map-lane map-execution">
|
||||
<span class="lane-label">TAILSCALE / PHYSICAL WORKER</span>
|
||||
<article class="system-node node-workspace" data-node="workspace">
|
||||
<small>06 / USER BOUNDARY</small>
|
||||
<strong>Per-user Workspace</strong>
|
||||
<span>Container · Network · Persistent volume</span>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flow-explainer" aria-live="polite">
|
||||
<span id="flow-kicker">AGENT REQUEST / 7 HOPS</span>
|
||||
<p id="flow-description">
|
||||
浏览器的已登录请求由 Web 转换成兼容 OpenAI 的流式调用;Runtime
|
||||
独立完成上下文构建、模型调用、工具循环和证据校验。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="boundary-grid">
|
||||
<article>
|
||||
<span class="boundary-number">A</span>
|
||||
<h3>Open WebUI</h3>
|
||||
<p>负责用户系统、会话、历史和呈现。它是产品外壳,不决定 Agent 如何思考与执行。</p>
|
||||
<small>STABLE / UPSTREAM-BASED</small>
|
||||
</article>
|
||||
<article>
|
||||
<span class="boundary-number">B</span>
|
||||
<h3>Agent Runtime</h3>
|
||||
<p>负责模型、上下文、工具、并行、委派、记忆和完成判定,是我们主要的实验面。</p>
|
||||
<small>FAST-MOVING / OWNED</small>
|
||||
</article>
|
||||
<article>
|
||||
<span class="boundary-number">C</span>
|
||||
<h3>Gateway + Workspace</h3>
|
||||
<p>把已验证用户绑定到唯一执行空间,控制路径、资源和 Docker 生命周期。</p>
|
||||
<small>SECURITY BOUNDARY</small>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section loop-section" id="agent-loop">
|
||||
<div class="section-heading inverse-heading">
|
||||
<div>
|
||||
<span class="section-index">03 / AGENT LOOP</span>
|
||||
<h2>模型不是 Agent,<br />循环才是。</h2>
|
||||
</div>
|
||||
<p>
|
||||
当前基线为 <code>agent-loop-v3</code>。模型每轮可以回答或提出工具调用;Runtime
|
||||
负责校验、调度、恢复,并拒绝没有证据的“已完成”。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="loop-console">
|
||||
<div class="loop-stages" role="tablist" aria-label="Agent Loop 阶段">
|
||||
<button class="loop-stage is-active" type="button" data-stage="context">
|
||||
<span>01</span><strong>Context</strong><small>裁剪与记忆</small>
|
||||
</button>
|
||||
<button class="loop-stage" type="button" data-stage="model">
|
||||
<span>02</span><strong>Model</strong><small>生成意图</small>
|
||||
</button>
|
||||
<button class="loop-stage" type="button" data-stage="validate">
|
||||
<span>03</span><strong>Validate</strong><small>规范与限制</small>
|
||||
</button>
|
||||
<button class="loop-stage" type="button" data-stage="schedule">
|
||||
<span>04</span><strong>Schedule</strong><small>并行与串行</small>
|
||||
</button>
|
||||
<button class="loop-stage" type="button" data-stage="execute">
|
||||
<span>05</span><strong>Execute</strong><small>工具与委派</small>
|
||||
</button>
|
||||
<button class="loop-stage" type="button" data-stage="evidence">
|
||||
<span>06</span><strong>Evidence</strong><small>验证与完成</small>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="loop-detail">
|
||||
<div>
|
||||
<span class="detail-label" id="stage-kicker">CONTEXT / recent-visible-v1</span>
|
||||
<h3 id="stage-title">把有限上下文留给真正影响下一步的内容</h3>
|
||||
</div>
|
||||
<p id="stage-description">
|
||||
移除旧的工具详情渲染,按模型预算保留最新可见消息,再注入最多 8
|
||||
条持久记忆。上下文策略和 Agent Loop 分别版本化。
|
||||
</p>
|
||||
<ul id="stage-points">
|
||||
<li>去掉历史消息中的工具 UI 标记</li>
|
||||
<li>最近消息优先,按字符预算截断</li>
|
||||
<li>记忆只作为补充上下文,不直接取得执行权限</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="loop-principles">
|
||||
<article>
|
||||
<span>PARALLELISM</span>
|
||||
<h3>只并行已知安全的读取</h3>
|
||||
<p>
|
||||
连续的只读、<code>parallel_safe</code> 工具可以并发;写入和状态变更保持顺序,
|
||||
避免输出更快但结果不可复现。
|
||||
</p>
|
||||
</article>
|
||||
<article>
|
||||
<span>RECOVERY</span>
|
||||
<h3>失败不是上下文噪声</h3>
|
||||
<p>命令失败必须被修复并重新运行,重复无进展调用会被守卫阻止,模型不能用文字绕过失败。</p>
|
||||
</article>
|
||||
<article>
|
||||
<span>DELEGATION</span>
|
||||
<h3>委派是受限的工具</h3>
|
||||
<p>只读子任务可并行,子 Agent 不能继续委派。父循环仍然负责整合证据和最终完成判定。</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="evidence-table" aria-label="完成证据规则">
|
||||
<div class="table-row table-head">
|
||||
<span>声称完成的类型</span><span>最低证据</span><span>阻止条件</span>
|
||||
</div>
|
||||
<div class="table-row">
|
||||
<strong>生成文件</strong><span>成功写入 + 随后读取或列出</span><span>只有模型文字</span>
|
||||
</div>
|
||||
<div class="table-row">
|
||||
<strong>修改代码</strong><span>变更操作 + 相关验证</span><span>未解决的失败命令</span>
|
||||
</div>
|
||||
<div class="table-row">
|
||||
<strong>生成报告</strong><span>来源或执行结果 + 报告文件验证</span><span>报告早于实验</span>
|
||||
</div>
|
||||
<div class="table-row">
|
||||
<strong>性能比较</strong><span>可解析的精确数值</span><span>只有定性结论</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section workspace-section" id="workspace">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<span class="section-index">04 / EXECUTION SPACE</span>
|
||||
<h2>每个用户,一套<br />长期存在的工具台</h2>
|
||||
</div>
|
||||
<p>
|
||||
生产执行发生在物理机 <code>home-node-itx</code>。Gateway 通过 Tailscale + SSH
|
||||
管理 Docker;用户得到独立容器、网络和持久卷,而不是宿主机账号。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="isolation-visual">
|
||||
<div class="identity-card">
|
||||
<small>IMMUTABLE INPUT</small>
|
||||
<strong>Open WebUI user_id</strong>
|
||||
<code>sha256(user_id) → workspace_id</code>
|
||||
</div>
|
||||
<div class="identity-arrow" aria-hidden="true">→</div>
|
||||
<div class="workspace-stack">
|
||||
<div><span>CONTAINER</span><code>k1412-ws-<id></code></div>
|
||||
<div><span>NETWORK</span><code>k1412-ws-net-<id></code></div>
|
||||
<div><span>VOLUME</span><code>k1412-ws-data-<id></code></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="security-grid">
|
||||
<article>
|
||||
<span class="security-icon">01</span>
|
||||
<h3>身份不下放给浏览器</h3>
|
||||
<p>Web 验证登录,Runtime 每次调用 Gateway 前重新签发短期身份。内部服务密钥从不进入前端。</p>
|
||||
</article>
|
||||
<article>
|
||||
<span class="security-icon">02</span>
|
||||
<h3>容器不是主机边界的替代品</h3>
|
||||
<p>只读根目录、丢弃 capabilities、no-new-privileges、资源限制、无宿主端口和 Docker socket。</p>
|
||||
</article>
|
||||
<article>
|
||||
<span class="security-icon">03</span>
|
||||
<h3>依赖和文件都会留下</h3>
|
||||
<p><code>/workspace</code> 由命名卷持久化;Python 位于 <code>.venv</code>,镜像升级不会删除用户数据。</p>
|
||||
</article>
|
||||
<article>
|
||||
<span class="security-icon">04</span>
|
||||
<h3>输出可以直接取回</h3>
|
||||
<p>工作区抽屉支持浏览、下载文件和流式归档。用户无需接触 Gateway、SSH 或容器名称。</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section models-section" id="models">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<span class="section-index">05 / MODEL POLICY</span>
|
||||
<h2>先标清模型,<br />再标真实思考能力</h2>
|
||||
</div>
|
||||
<p>
|
||||
Luna、Terra、Sol 是三个独立模型,不是同一模型的轻、中、高强度。前端只显示后端确认支持的
|
||||
思考语义;provider、循环和上下文预算仍由服务端模型目录固定。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="model-grid">
|
||||
<article class="model-card">
|
||||
<div><span class="model-dot luna"></span><small>LOCAL MODEL</small></div>
|
||||
<h3>Luna</h3>
|
||||
<p>思考:开启(不分档)</p>
|
||||
<dl><div><dt>循环上限</dt><dd>8</dd></div><div><dt>上下文预算</dt><dd>120k chars</dd></div></dl>
|
||||
</article>
|
||||
<article class="model-card is-default">
|
||||
<div><span class="model-dot terra"></span><small>LOCAL / DEFAULT</small></div>
|
||||
<h3>Terra</h3>
|
||||
<p>思考:开启(不分档)</p>
|
||||
<dl><div><dt>循环上限</dt><dd>16</dd></div><div><dt>上下文预算</dt><dd>240k chars</dd></div></dl>
|
||||
</article>
|
||||
<article class="model-card">
|
||||
<div><span class="model-dot sol"></span><small>LOCAL MODEL</small></div>
|
||||
<h3>Sol</h3>
|
||||
<p>思考:开启(不分档)</p>
|
||||
<dl><div><dt>循环上限</dt><dd>24</dd></div><div><dt>上下文预算</dt><dd>400k chars</dd></div></dl>
|
||||
</article>
|
||||
<article class="model-card model-deepseek">
|
||||
<div><span class="model-dot deepseek"></span><small>CLOUD / MAX EFFORT</small></div>
|
||||
<h3>DeepSeek V4 Pro</h3>
|
||||
<p>思考强度:极高(max)</p>
|
||||
<dl><div><dt>循环上限</dt><dd>32</dd></div><div><dt>上下文预算</dt><dd>800k chars</dd></div></dl>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="policy-note">
|
||||
<span>命名规则</span>
|
||||
<p>
|
||||
<strong>Luna / Terra / Sol / DeepSeek V4 Pro</strong> 是四个独立模型。前三者目前只暴露
|
||||
“思考开启”的布尔能力,不能严谨地标成轻、中、高;DeepSeek 才明确使用
|
||||
<strong>reasoning_effort=max</strong>,界面标注为“极高”。
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section experiments-section" id="experiments">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<span class="section-index">06 / EXPERIMENT LOG</span>
|
||||
<h2>每次改进都应该<br />留下可比较的记录</h2>
|
||||
</div>
|
||||
<p>
|
||||
实验以问题、基线、变量、数据集、指标和结论为最小单元。页面读取仓库里的
|
||||
<code>experiments.json</code>,与实现一起版本化。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="experiment-toolbar">
|
||||
<div class="filter-group" role="group" aria-label="实验状态筛选">
|
||||
<button class="filter-button is-active" type="button" data-filter="all">全部</button>
|
||||
<button class="filter-button" type="button" data-filter="baseline">基线</button>
|
||||
<button class="filter-button" type="button" data-filter="validated">已验证</button>
|
||||
<button class="filter-button" type="button" data-filter="backlog">待实验</button>
|
||||
</div>
|
||||
<label class="experiment-search">
|
||||
<span class="sr-only">搜索实验</span>
|
||||
<input id="experiment-search" type="search" placeholder="搜索上下文、并行、记忆…" />
|
||||
<span aria-hidden="true">⌕</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="experiment-grid" id="experiment-grid" aria-live="polite">
|
||||
<article class="experiment-loading">正在读取实验台账…</article>
|
||||
</div>
|
||||
<p class="experiment-count" id="experiment-count"></p>
|
||||
</section>
|
||||
|
||||
<section class="section operations-section" id="operations">
|
||||
<div class="section-heading inverse-heading">
|
||||
<div>
|
||||
<span class="section-index">07 / OPERATIONS</span>
|
||||
<h2>一条公开入口,<br />多层私有服务</h2>
|
||||
</div>
|
||||
<p>
|
||||
生产栈运行于 Unraid NAS,公开流量经 VPS 上的 Nginx Proxy Manager 和 Tailscale
|
||||
进入 NAS。文档和聊天由同一个 Web 镜像提供。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="deployment-path" aria-label="部署链路">
|
||||
<div><small>GIT</small><strong>git.k1412.top</strong></div>
|
||||
<span>→</span>
|
||||
<div><small>OCI</small><strong>docker.k1412.top</strong></div>
|
||||
<span>→</span>
|
||||
<div><small>COMPOSE</small><strong>Unraid NAS :12004</strong></div>
|
||||
<span>→</span>
|
||||
<div><small>PUBLIC</small><strong>agent.k1412.top</strong></div>
|
||||
</div>
|
||||
|
||||
<div class="ops-grid">
|
||||
<article>
|
||||
<span>01 / BUILD</span>
|
||||
<h3>不可变镜像</h3>
|
||||
<p>镜像按 UTC 时间与 Git commit 标记;发布只替换发生变化的服务。</p>
|
||||
</article>
|
||||
<article>
|
||||
<span>02 / VERIFY</span>
|
||||
<h3>分层验证</h3>
|
||||
<p>静态检查、单元测试、真实 Docker、完整 E2E、镜像审计与公开路径冒烟。</p>
|
||||
</article>
|
||||
<article>
|
||||
<span>03 / OBSERVE</span>
|
||||
<h3>事件优先</h3>
|
||||
<p>每轮上下文、模型、工具和完成状态进入运行事件,便于重放与实验比较。</p>
|
||||
</article>
|
||||
<article>
|
||||
<span>04 / ROLLBACK</span>
|
||||
<h3>保留上个版本</h3>
|
||||
<p>配置先备份,旧镜像不覆盖;验证失败时恢复镜像引用即可回退。</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section timeline-section" id="timeline">
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<span class="section-index">08 / PROJECT HISTORY</span>
|
||||
<h2>从业务 Agent 到<br />通用实验平台</h2>
|
||||
</div>
|
||||
<p>
|
||||
项目按“干净重建”推进,不保留旧业务 Skill 和旧 API 兼容层。下面记录已经改变系统性质的关键决策。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ol class="timeline">
|
||||
<li>
|
||||
<span>01</span>
|
||||
<div><small>FOUNDATION</small><h3>重建为多人 Web Agent</h3><p>Open WebUI 承担账户和聊天外壳,自研 Runtime 承担 Agent 能力。</p></div>
|
||||
</li>
|
||||
<li>
|
||||
<span>02</span>
|
||||
<div><small>PRODUCT</small><h3>收敛为单一 Agent 路径</h3><p>删除 Chat / Work 双模式,降低交互和后端维护成本。</p></div>
|
||||
</li>
|
||||
<li>
|
||||
<span>03</span>
|
||||
<div><small>EXECUTION</small><h3>迁移到远端持久工作区</h3><p>接入 home-node-itx,打通每用户容器、持久卷与文件交付。</p></div>
|
||||
</li>
|
||||
<li>
|
||||
<span>04</span>
|
||||
<div><small>RELIABILITY</small><h3>建立证据驱动的完成策略</h3><p>加入恢复、重试守卫、精确报告证据和结构化事件。</p></div>
|
||||
</li>
|
||||
<li>
|
||||
<span>05</span>
|
||||
<div><small>PLATFORM</small><h3>补齐 Python 环境与长期身份</h3><p>持久化虚拟环境、pipefail、900 秒工具超时和每次调用的新鲜身份令牌。</p></div>
|
||||
</li>
|
||||
<li class="is-current">
|
||||
<span>06</span>
|
||||
<div><small>NOW</small><h3>文档与实验成为产品界面</h3><p>架构、实现、运维和实验台账随代码发布到同域门户。</p></div>
|
||||
</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section class="section repository-section" id="repository">
|
||||
<div class="repository-panel">
|
||||
<div>
|
||||
<span class="section-index">09 / REPOSITORY</span>
|
||||
<h2>网页负责建立心智模型,<br />仓库文档负责成为事实来源。</h2>
|
||||
<p>
|
||||
所有设计说明、限制、运维步骤和实验规范都与代码一同提交。门户是摘要,
|
||||
Markdown 文档是评审与变更时的正式依据。
|
||||
</p>
|
||||
<a class="button button-light" href="https://git.k1412.top/wuyang/zk-data-agent">
|
||||
打开 Git 仓库 <span aria-hidden="true">↗</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="doc-list">
|
||||
<a href="https://git.k1412.top/wuyang/zk-data-agent">
|
||||
<span>README.md</span><small>产品入口与快速开始</small>
|
||||
</a>
|
||||
<a href="https://git.k1412.top/wuyang/zk-data-agent">
|
||||
<span>docs/architecture.md</span><small>系统边界与请求生命周期</small>
|
||||
</a>
|
||||
<a href="https://git.k1412.top/wuyang/zk-data-agent">
|
||||
<span>docs/agent-loop.md</span><small>Loop、调度、证据与委派</small>
|
||||
</a>
|
||||
<a href="https://git.k1412.top/wuyang/zk-data-agent">
|
||||
<span>docs/experiments.md</span><small>实验方法与路线图</small>
|
||||
</a>
|
||||
<a href="https://git.k1412.top/wuyang/zk-data-agent">
|
||||
<span>docs/operations.md</span><small>发布、恢复与故障处理</small>
|
||||
</a>
|
||||
<a href="https://git.k1412.top/wuyang/zk-data-agent">
|
||||
<span>docs/security.md</span><small>威胁边界与安全控制</small>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<span>K1412 AGENT / SYSTEM NOTES</span>
|
||||
<p>代码、文档与实验共同演进。</p>
|
||||
<a href="#overview">回到顶部 ↑</a>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user