这是indexloc提供的服务,不要输入任何密码
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 73 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,25 @@

</div>

ACP (Agent Control Plane) is a cloud-native orchestrator for AI Agents built on Kubernetes. It supports [long-lived outer-loop agents](https://theouterloop.substack.com/p/openais-realtime-api-is-a-step-towards) that can process asynchronous execution of both LLM inference and long-running tool calls. It's designed for simplicity and gives strong durability and reliability guarantees for agents that make asynchronous tool calls like contacting humans or delegating work to other agents.
## Introduction

Agent Control Plane (ACP) is a cloud-native orchestrator for AI Agents built on Kubernetes. It's designed to help you build production-grade AI systems that are reliable, scalable, and maintainable.

After building and deploying AI agents in production environments, we've learned that the most successful implementations are those that combine well-engineered software with strategic LLM integration. ACP embodies these lessons by providing:

- **Durable Execution**: Built-in support for long-running, asynchronous operations with automatic checkpointing and recovery
- **Human-in-the-Loop**: Seamless integration with human approval workflows and input channels
- **Observability**: Comprehensive tracing and monitoring of agent execution
- **Scalability**: Kubernetes-native architecture for reliable distributed agent execution
- **Flexibility**: Support for multiple LLM providers and tool integration patterns

ACP is particularly useful when you need to:
- Build agents that incorporate long-running tool calls reliably
- Incorporate human approval into your agent workflows
- Scale agent execution across a distributed system
- Maintain clear visibility into agent behavior and execution state

Whether you're building a new AI-powered application or enhancing an existing system, ACP provides the infrastructure needed to deploy production-ready AI agents.

:warning: **Note** - ACP is in alpha. Use at your own risk.

Expand Down Expand Up @@ -1109,6 +1127,7 @@ Events:
Normal AllToolCallsCompleted 7s task-controller All tool calls completed, ready to send tool results to LLM
Normal LLMFinalAnswer 6s task-controller LLM response received successfully
```

### Open Telemetry support

You can use the `acp-example` folder to spin up a cluster with an otel stack, to view Task execution traces in grafana + tempo
Expand Down Expand Up @@ -1217,3 +1236,56 @@ ACP is open-source and we welcome contributions in the form of issues, documenta
## License

ACP is licensed under the Apache 2 License.





Writing



Howdy HN - I'm Dex from HumanLayer (YC F24), and I've been building AI agents for a while. After trying every framework out there and talking to many founders building with AI, I've noticed something interesting: most "AI Agents" that make it to production aren't actually that agentic. The best ones are mostly just well-engineered software with LLMs sprinkled in at key points.
So I set out to document what I've learned about building production-grade AI systems. Today I'm excited to share "12 Factor Agents"

https://github.com/humanlayer/12-factor-agents

It's a set of principles for building LLM-powered software that's reliable enough to put in the hands of production customers.

I've seen many SaaS builders try to pivot towards AI by building greenfield new projects on agent frameworks, only to find that they couldn't get things past the 70-80% reliability bar with out-of-the-box tools. The ones that did succeed tended to take small, modular concepts from agent building, and incorporate them into their existing product, rather than starting from scratch.

In the spirit of Heroku's 12 Factor Apps (https://12factor.net/), these principles focus on the engineering practices that make LLM applications more reliable, scalable, and maintainable. Even as models get exponentially more powerful, these core techniques will remain valuable.

Some highlights:

- Factor 1: Natural Language to Tool Calls

- Factor 2: Own your prompts

- Factor 3: Own your context window

- Factor 4: Tools are just structured outputs

- Factor 5: Unify execution and business state

- Factor 6: Launch/Pause/Resume with simple APIs

- Factor 7: Contact humans with tool calls

- Factor 8: Own your control flow

- Factor 9: Compact errors into context

- Factor 10: Small, focused agents

- Factor 11: Meet users where they are

- Factor 12: Make your agent a stateless reducer

The full guide goes into detail on each principle with examples and patterns to follow. I've seen these practices work well in production systems handling real user traffic.

I'm sharing this as a starting point - the field is moving quickly and I expect these principles to evolve. I welcome your feedback and contributions to help figure out what "production grade" means for AI systems.

Check out the full guide at https://github.com/humanlayer/12-factor-agents

Special thanks to (github users) @iantbutler01, @tnm, @hellovai, @stantonk, @balanceiskey, @AdjectiveAllison, @pfbyjy, @a-churchill, as well as the SF MLOps community for early feedback on this guide.
92 changes: 92 additions & 0 deletions acp/api/v1alpha1/agent_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,90 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// ExecuteConfig defines the configuration for freestyle execution
type ExecuteConfig struct {
// APIKeyFrom references the secret containing the API key
// +kubebuilder:validation:Required

// +optional
FreestyleConfig *FreestyleConfig `json:"freestyle,omitempty"`
// E2BConfig *E2BConfig `json:"e2b,omitempty"`
// +optional
SecretSelectors []SecretSelector `json:"secretSelectors,omitempty"`
// optional - restrict the npm packages that can be used
// by default, all packages are allowed
// +optional
AllowedNPMPackages []string `json:"allowedNPMPackages,omitempty"`
}

/**

execute:
secretSelectors:
# todo is this an AND or an OR?
- name: code-execution-secret
- matchLabels:
environment: development
freestyle:
apiKeyFrom:
name: freestyle-api-key
key: apiKey

*/

/**

tool description:
name: code-execution
description: This tool is used to execute code
parameters:
type: object
properties:
code:
type: string
description: The code to execute
npmPackages:
type: array
items:
type: object
// todo can we do dynamic k:v or has to be array?
properties:
name:
type: string
description: The name of the npm package
version:
type: string
description: The version of the npm package
secrets:
type: array
items:
type: string
description: array of secrets to pass in as env vars, e.g. RESEND_API_KEY

*/

type SecretSelector struct {
// Name of the secret
// +kubebuilder:validation:Required
Name string `json:"name"`

// MatchLabels is a map of labels that the secret must have
// +optional
MatchLabels map[string]string `json:"matchLabels,omitempty"`
}

type FreestyleConfig struct {
// APIKeyFrom references the secret containing the API key
// +kubebuilder:validation:Required
APIKeyFrom SecretKeyRef `json:"apiKeyFrom"`
}

type E2BConfig struct {
// APIKeyFrom references the secret containing the API key
// +kubebuilder:validation:Required
APIKeyFrom SecretKeyRef `json:"apiKeyFrom"`
}

// AgentSpec defines the desired state of Agent
type AgentSpec struct {
// LLMRef references the LLM to use for this agent
Expand All @@ -22,6 +106,10 @@ type AgentSpec struct {
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
System string `json:"system"`

// Execute defines how the agent should execute code
// +optional
Execute *ExecuteConfig `json:"execute,omitempty"`
}

// LocalObjectReference contains enough information to locate the referenced resource in the same namespace
Expand Down Expand Up @@ -97,3 +185,7 @@ type AgentList struct {
metav1.ListMeta `json:"metadata,omitempty"`
Items []Agent `json:"items"`
}

func init() {
SchemeBuilder.Register(&Agent{}, &AgentList{})
}
5 changes: 3 additions & 2 deletions acp/api/v1alpha1/toolcall_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ const (
type ToolType string

const (
ToolTypeMCP ToolType = "MCP"
ToolTypeHumanContact ToolType = "HumanContact"
ToolTypeMCP ToolType = "MCP"
ToolTypeHumanContact ToolType = "HumanContact"
ToolTypeExecuteToolType ToolType = "ExecuteScript"
)

// ToolCallSpec defines the desired state of ToolCall
Expand Down
21 changes: 21 additions & 0 deletions acp/api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions acp/config/crd/bases/acp.humanlayer.dev_agents.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,26 @@ spec:
spec:
description: AgentSpec defines the desired state of Agent
properties:
execute:
description: Execute defines how the agent should execute code
properties:
freestyleApiKeyFrom:
description: APIKeyFrom references the secret containing the API
key
properties:
key:
description: Key is the key in the secret
type: string
name:
description: Name is the name of the secret
type: string
required:
- key
- name
type: object
required:
- freestyleApiKeyFrom
type: object
humanContactChannels:
description: HumanContactChannels is a list of ContactChannel resources
that can be used for human interactions
Expand Down
2 changes: 1 addition & 1 deletion acp/config/manager/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ kind: Kustomization
images:
- name: controller
newName: controller
newTag: "202504102058"
newTag: "202504110028"
16 changes: 16 additions & 0 deletions acp/internal/controller/agent/agent_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,22 @@ func (r *AgentReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl
statusUpdate.Status.ValidMCPServers = validMCPServers
}

if agent.Spec.Execute != nil {
secret := &corev1.Secret{}
err = r.Get(ctx, client.ObjectKey{
Namespace: agent.Namespace,
Name: agent.Spec.Execute.APIKeyFrom.Name,
}, secret)
if err != nil {
return r.setStatusError(ctx, &agent, err, statusUpdate, "ValidationFailed")
}

if _, ok := secret.Data[agent.Spec.Execute.APIKeyFrom.Key]; !ok {
return r.setStatusError(ctx, &agent, fmt.Errorf("API key secret %q does not have key %q", agent.Spec.Execute.APIKeyFrom.Name, agent.Spec.Execute.APIKeyFrom.Key), statusUpdate, "ValidationFailed")
}
logger.Info("Freestyle API key secret validated")
}

// Validate HumanContactChannel references, if any
if len(agent.Spec.HumanContactChannels) > 0 {
validHumanContactChannels, err = r.validateHumanContactChannels(ctx, &agent)
Expand Down
Loading
Loading