Skip to content

Commit

Permalink
Update code samples and improve concepts documentation (#48)
Browse files Browse the repository at this point in the history
* docs(concepts): update and improve Routers documentation

* docs(concepts): some fixes and small improvements on Agents

* docs(concepts): refresh Networks docs

* docs(concepts): update the Models docs

* docs: review the early access callout on the index page

* docs(overview): update code samples + wording fixes

* docs(references): update

* docs(references): add a Models reference

* docs: update internal links

* docs: add example links

* docs: hide guides for now

* Update docs/concepts/networks.mdx

Co-authored-by: Dan Farrelly <[email protected]>

* Update docs/concepts/networks.mdx

Co-authored-by: Dan Farrelly <[email protected]>

* docs: wording fix

---------

Co-authored-by: Dan Farrelly <[email protected]>
  • Loading branch information
charlypoly and djfarrelly authored Jan 16, 2025
1 parent 83ac222 commit 7e1df83
Show file tree
Hide file tree
Showing 18 changed files with 995 additions and 156 deletions.
38 changes: 30 additions & 8 deletions docs/concepts/agents.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Agents
description: Create
description: Create agents to accomplish specific tasks with tools inside a network.
icon: 'head-side-gear'
iconType: 'regular'
---
Expand All @@ -13,7 +13,9 @@ At the most basic level, an Agent is a wrapper around a specific provider's [mod

## Creating an Agent

To create a simple Agent, all that you need is a `name`, `system` prompt and a `model`. All configuration options are detailed in the `createAgent` [reference](/reference/agent). Here is a simple agent created using the `createAgent` function:
To create a simple Agent, all that you need is a `name`, `system` prompt and a `model`. All configuration options are detailed in the `createAgent` [reference](/reference/agent).

Here is a simple agent created using the `createAgent` function:

```ts
import { createAgent, openai } from '@inngest/agent-kit';
Expand Down Expand Up @@ -58,12 +60,12 @@ console.log(output);

[Tools](/concepts/tools) are functions that extend the capabilities of an Agent. Along with the prompt (see `run()`), Tools are included in calls to the language model through features like OpenAI's "[function calling](https://platform.openai.com/docs/guides/function-calling)" or Claude's "[tool use](https://docs.anthropic.com/en/docs/build-with-claude/tool-use)."

Tools are defined using the `createTypedTool` function and are passed to agents via the `tools` parameter:
Tools are defined using the `createTool` function and are passed to agents via the `tools` parameter:

```ts
import { createAgent, createTypedTool, openai } from '@inngest/agent-kit';
import { createAgent, createTool, openai } from '@inngest/agent-kit';

const listChargesTool = createTypedTool({
const listChargesTool = createTool({
name: 'list_charges',
description:
"Returns all of a user's charges. Call this whenever you need to find one or more charges between a date range.",
Expand Down Expand Up @@ -106,7 +108,7 @@ Agents themselves are relatively simple. When you call `run()`, there are severa
</Step>
<Step title="Inference call">
{/* TODO - Update this when Inngest isn't a requirement */}
An inference call is made to the provided [`model`](/concepts/models) using Inngest's `step.ai`. `step.ai` automatically retries on failure and caches the result for durability.
An inference call is made to the provided [`model`](/concepts/models) using Inngest's [`step.ai`](https://www.inngest.com/docs/features/inngest-functions/steps-workflows/step-ai-orchestration#step-tools-step-ai). `step.ai` automatically retries on failure and caches the result for durability.

The result is parsed into an `InferenceResult` object that contains all messages, tool calls and the raw API response from the model.

Expand All @@ -130,7 +132,27 @@ Agents themselves are relatively simple. When you call `run()`, there are severa

### Lifecycle hooks

Agent lifecycle hooks can be used to intercept and modify how an Agent works enabling dynamic control over the system. As mentioned in the "[How Agents work](#how-agents-work)" section, there are a few lifecycle hooks that can be defined on the Agent's `lifecycle` options object.
Agent lifecycle hooks can be used to intercept and modify how an Agent works enabling dynamic control over the system:

```tsx
import { createAgent, openai } from '@inngest/agent-kit';

const agent = createAgent({
name: 'Code writer',
description: 'An expert TypeScript programmer which can write and debug code.',
system: '...',
model: openai('gpt-3.5-turbo'),
lifecycle: {
onStart: async ({ prompt, network: { state }, history }) => {
// Dynamically alter prompts using Network state and history.

return { prompt, history }
},
},
});
```

As mentioned in the "[How Agents work](#how-agents-work)" section, there are a few lifecycle hooks that can be defined on the Agent's `lifecycle` options object.

- Dynamically alter prompts using Network [State](/concepts/state) or the Network's history.
- Parse output of model after an inference call.
Expand All @@ -145,7 +167,7 @@ An Agent's system prompt can be defined as a string or an async callback. When A

Dynamic system prompts are very useful in agentic workflows, when multiple models are called in a loop, prompts can be adjusted based on network state from other call outputs.

```ts Dynamic system prompt
```ts
const agent = createAgent({
name: 'Code writer',
description:
Expand Down
69 changes: 50 additions & 19 deletions docs/concepts/models.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,46 +15,71 @@ import { openai, anthropic, gemini } from "@inngest/agent-kit";

## How to use a model

### Create a model instance

<Info>
Each model helper will first try to get the API Key from the environment variable.
The API Key can also be provided with the `apiKey` option to the model helper.
</Info>

<CodeGroup>

```ts OpenAI
import { openai, createAgent } from "@inngest/agent-kit";

const supportAgent = createAgent({
model: openai("gpt-3.5-turbo"),
name: "Customer support specialist",
system: "You are an customer support specialist...",
tools: [listChargesTool],
});
const model = openai('gpt-3.5-turbo')
const modelWithApiKey = openai('gpt-3.5-turbo', { apiKey: 'sk-...' })
```

```ts Anthropic
import { anthropic, createAgent } from "@inngest/agent-kit";
import { anthropic, createAgent } from '@inngest/agent-kit';

const supportAgent = createAgent({
model: anthropic("claude-3-5-haiku-latest"),
name: "Customer support specialist",
system: "You are an customer support specialist...",
tools: [listChargesTool],
});
const model = anthropic('claude-3-5-haiku-latest')

const modelWithMaxTokens = anthropic('claude-3-5-haiku-latest', { maxTokens: 1000 })

const modelWithBetaFlags = anthropic('claude-3-5-haiku-latest', { betaHeaders: ["prompt-caching-2024-07-31"] })

const modelWithApiKey = anthropic('claude-3-5-haiku-latest', { apiKey: 'sk-...' })
```

```ts Gemini
import { gemini, createAgent } from "@inngest/agent-kit";
import { gemini, createAgent } from '@inngest/agent-kit';

const model = gemini('gemini-1.5-flash')
```

</CodeGroup>

### Providing a model instance to an Agent

```ts
import { createAgent } from '@inngest/agent-kit';

const supportAgent = createAgent({
model: gemini("claude-3-5-haiku-latest"),
model: openai("gpt-3.5-turbo"),
name: "Customer support specialist",
system: "You are an customer support specialist...",
tools: [listChargesTool],
});
```

</CodeGroup>

{// TODO:
// - How models are called
}
### Providing a model instance to a Network

<Info>
The provided `defaultModel` will be used for all Agents without a model specified.
It will also be used by the "[Default Routing Agent](/concepts/routers#default-routing-agent-autonomous-routing)" if enabled.
</Info>

```ts
import { createNetwork } from '@inngest/agent-kit';

const network = createNetwork({
agents: [supportAgent],
defaultModel: openai('gpt-4o'),
});
```

## List of supported models

Expand Down Expand Up @@ -98,6 +123,12 @@ For a full list of supported models, you can always check [the models directory

</CodeGroup>

### Environment variable used for each model provider

- OpenAI: `OPENAI_API_KEY`
- Anthropic: `ANTHROPIC_API_KEY`
- Gemini: `GEMINI_API_KEY`

## Contribution

Is there a model that you'd like to see included in AgentKit? Open an issue, create a pull request, or chat with the team on [Discord in the #ai channel](https://www.inngest.com/community).
Expand Down
156 changes: 136 additions & 20 deletions docs/concepts/networks.mdx
Original file line number Diff line number Diff line change
@@ -1,42 +1,39 @@
---
title: Networks
description: 'Combine one or more agents into a Network'
description: 'Combine one or more agents into a Network.'
icon: 'chart-network'
iconType: 'regular'
---

Networks are **Systems of [Agents](/concepts/agents)**. Use Networks to create complex, stateful workflows with one or more Agents.
Networks are **Systems of [Agents](/concepts/agents)**. Use Networks to create powerful AI workflows by combining multiple Agents.

A network contains three components:

- The Agents that the network can access
- [State](/concepts/state), including past messages and a key value store
- A [Router](/concepts/routers), which chooses whether to quit or the next agent to run in the loop

It also has an optional default model, which will be used when your Agents have no model provided, and a setting to cap the number of model calls via `maxIter`.
- The [Agents](/concepts/agents) that the network can use to achieve a goal
- A [State](/concepts/state) including past messages and a key value store, shared between Agents and the Router
- A [Router](/concepts/routers), which chooses whether to stop or select the next agent to run in the loop

Here's a simple example:

```tsx
import { createNetwork, openai } from '@inngest/agent-kit';

// searchAgent and summaryAgent definitions...

// Create a network with two agents.
const network = createNetwork({
agents: [searchAgent, summaryAgent],
// Optional: used for routing and agents if they have no model
defaultModel: openai({ model: 'gpt-4o', step }),
maxIter: 10, // Optional: max number of agent calls
});

// Run the network with a user prompt
await network.run('What happened in the 2024 Super Bowl?');
```

Similar to agents, you call `run()` on a network with some user input. The network then runs a core loop to call one or more agents to find a suitable answer.
By calling `run()`, the network runs a core loop to call one or more agents to find a suitable answer.

## How Networks work

Networks can be thought of as while loops with memory that call Agents and Tools until the Router determines that there is no more work to be done.
Networks can be thought of as while loops with memory ([State](/concepts/state)) that call Agents and Tools until the Router determines that there is no more work to be done.

<Steps>
<Step title="Create the Network of Agents">
Expand Down Expand Up @@ -70,11 +67,130 @@ Networks can be thought of as while loops with memory that call Agents and Tools
</Steps>
</Step>
</Steps>
{
// TODO
// - Purpose of a network
// - How state is core to the Network (minimal explainer - link to State concept doc)
// - Routing - what is a router and what is it's purpose within a Network, default router vs. custom routing - link to deeper routing guide
}

## Routing

## Model configuration

A Network must provide a default model which is used for routing between Agents and for Agents that don't have one:

```tsx
import { createNetwork, openai } from '@inngest/agent-kit';

// searchAgent and summaryAgent definitions...

const network = createNetwork({
agents: [searchAgent, summaryAgent],
defaultModel: openai({ model: 'gpt-4o' }),
});
```

<Info>
A Network not defining a `defaultModel` and composed of Agents without model will throw an error.
</Info>

### Combination of multiple models

Each Agent can specify it's own model to use so a Network may end up using multiple models. Here is an example of a Network that defaults to use an OpenAI model, but the `summaryAgent` is configured to use an Anthropic model:

```tsx
import { createNetwork, openai, anthropic } from '@inngest/agent-kit';

const searchAgent = createAgent({
name: 'Search',
description: 'Search the web for information',
});

const summaryAgent = createAgent({
name: 'Summary',
description: 'Summarize the information',
model: anthropic({ model: 'claude-3-5-sonnet' }),
});

// The searchAgent will use gpt-4o, while the summaryAgent will use claude-3-5-sonnet.
const network = createNetwork({
agents: [searchAgent, summaryAgent],
defaultModel: openai({ model: 'gpt-4o' }),
});
```

## Routing & maximum iterations


### Routing

A Network can specify an optional `defaultRouter` function that will be used to determine the next Agent to run.

```ts
import { createNetwork } from '@inngest/agent-kit';

// classifier and writer Agents definition...

const network = createNetwork({
agents: [classifier, writer],
defaultRouter: ({ lastResult, callCount }) => {
// retrieve the last message from the output
const lastMessage = lastResult?.output[lastResult?.output.length - 1];
const content = lastMessage?.type === 'text' ? lastMessage?.content as string : '';
// First call: use the classifier
if (callCount === 0) {
return classifier;
}
// Second call: if it's a question, use the writer
if (callCount === 1 && content.includes('question')) {
return writer;
}
// Otherwise, we're done!
return undefined;
},
});
```


Refer to the [Router](/concepts/routers) documentation for more information about how to create a custom Router.

### Maximum iterations

A Network can specify an optional `maxIter` setting to limit the number of iterations.

```tsx
import { createNetwork } from '@inngest/agent-kit';

// searchAgent and summaryAgent definitions...

const network = createNetwork({
agents: [searchAgent, summaryAgent],
defaultModel: openai({ model: 'gpt-4o' }),
maxIter: 10,
});
```

<Info>
Specifying a `maxIter` option is useful when using a [Default Routing Agent](/concepts/routers#default-routing-agent-autonomous-routing) or a [Hybrid Router](/concepts/routers#hybrid-code-and-agent-routers-semi-supervised-routing) to avoid infinite loops.

A Routing Agent or Hybrid Router rely on LLM calls to make decisions, which means that they can sometimes fail to identify a final condition.
</Info>

### Combining `maxIter` and `defaultRouter`

You can combine `maxIter` and `defaultRouter` to create a Network that will stop after a certain number of iterations or when a condition is met.

However, please note that the `maxIter` option can prevent the `defaultRouter` from being called (For example, if `maxIter` is set to 1, the `defaultRouter` will only be called once).


## Providing a default State

A Network can specify an optional `defaultState` setting to provide a default [State](/concepts/state).

```tsx
import { createNetwork } from '@inngest/agent-kit';

// searchAgent and summaryAgent definitions...

const network = createNetwork({
agents: [searchAgent, summaryAgent],
defaultState: new State({
foo: 'bar',
}),
});
```

Providing a `defaultState` can be useful to persist the state in database between runs or initialize your network with external data.
Loading

0 comments on commit 7e1df83

Please sign in to comment.