# Recursive Neuro-Symbolic Inversion of Control

> I organized my thoughts on a pattern that takes advantage of the strengths of both systems through recursive inversion of control (IoC) between AI agents and traditional logic. It is also the common thread running through two recent attempts of mine (Semi-structured Software Specification (s4), Augmenting the Value Embedded in Process).

I organized my thoughts on a pattern that takes advantage of the strengths of both systems through recursive <inversion of control (IoC)> between AI agents and traditional logic. It is also the common thread running through two recent attempts of mine ([Semi-structured Software Specification (s4)](https://wiki.g15e.com/pages/Semi-structured%20software%20spec.txt), [Augmenting the Value Embedded in Process](https://wiki.g15e.com/en/pages/Augmenting%20values%20in%20the%20process.txt)).

## Tool Use by AI Agents and Inversion of Control

If the way traditional code calls an [LLM](https://wiki.g15e.com/pages/Large%20language%20model.txt) is forward control, then the way an [LLM](https://wiki.g15e.com/pages/Large%20language%20model.txt) calls code—that is, the way an AI agent uses tools—can be seen as <inversion of control>. Traditional code is symbolic computation, and LLMs are [artificial neural networks](https://wiki.g15e.com/pages/Artificial%20neural%20network.txt), so tool use by AI agents can be called a pattern of [neuro-symbolic inversion of control](https://wiki.g15e.com/pages/Neuro-Symbolic%20Inversion%20of%20Control.txt).

## Recursive Inversion of Control

In [Semi-structured Software Specification](https://wiki.g15e.com/pages/Semi-structured%20software%20spec.txt), `s4` is a traditional <CLI> program that statically analyzes source code together with a YAML specification (`s4.yaml`) following a specific format, and outputs what should be done next.

When you run `s4`,

1. whether the specification has internal consistency (for example, whether every business goal has one or more concrete features, whether there are no cycles in dependency relations among features, whether every feature has one or more acceptance criteria, etc.)
2. whether the specification and the code match (for example, whether acceptance tests corresponding to the acceptance criteria in the specification exist in the code)
3. whether all checks registered in the specification (acceptance tests, unit tests, coverage, type checking, etc.) pass

are examined, and if a problem is found, it outputs what the very first problem to solve is, what needs to be done to solve that problem, and so on.

Interesting things happen when you put this tool in an AI agent's hands.

1. The user gives the agent an instruction in natural language.
2. The AI agent is in charge of the most abstract, highest-level control. The agent decides when to call `s4`.
3. `s4` performs various checks according to fixed logic and outputs the results.
4. The AI agent uses the output of `s4` as a reference and performs the concrete work. At this stage, the agent also uses lower-level tools (diff, patch, [MCP](https://wiki.g15e.com/pages/Model%20context%20protocol.txt) server, etc.).

What happens between steps 3 and 4 is interesting: `s4` does not directly perform the concrete work (that is, the actual coding). Instead, it merely tells the AI agent what it should do. Technically speaking, `s4` simply outputs the analysis results as text, and the AI agent merely refers to them, but if we interpret what is actually happening semantically, we can see it as `s4` instructing the AI agent on what to do next, and the agent then carrying out the most concrete, lowest-level work (coding) accordingly.

 ```mermaid
 sequenceDiagram
	 autonumber
	 actor U as User
	 participant S as s4
	 participant A as Agent
	 
	 U ->>+ A: 명령
	 loop s4가 끝났다고 할 때까지
		 A ->>+ S: 호출
		 S -->>- A: 작업 지시
		 A ->> A: 지시에 따라 작업 수행
	 end
	 A -->>- U: 완료 보고
 ```

If interpreted from the perspective of [distributed functional decomposition](https://wiki.g15e.com/pages/Distributed%20functional%20decomposition.txt), this means that <inversion of control> has happened once again, in the direction of `s4` calling the agent and making it do work.

The general tool-use pattern of ordinary AI agents (non-recursive [neuro-symbolic inversion of control](https://wiki.g15e.com/pages/Neuro-Symbolic%20Inversion%20of%20Control.txt)) is as follows.

```mermaid
sequenceDiagram
	autonumber
	actor U as User
	participant C as Code
	participant A as Agent
	
	U ->>+ A: 명령
	loop Agent가 끝났다고 판단할 때까지
		A ->>+ C: 호출
		C -->>- A: 결과
	end
	A -->>- U: 생성된 출력
```

## Another Example

In [Augmenting the Value Embedded in Process](https://wiki.g15e.com/en/pages/Augmenting%20values%20in%20the%20process.txt), I introduce a case of mixing traditional graph analysis algorithms and an [LLM](https://wiki.g15e.com/pages/Large%20language%20model.txt) in the context of [wiki gardening](https://wiki.g15e.com/en/pages/Wiki%20gardening%20rules.txt).

1. When the user gives the AI agent an instruction at an abstract level ("I want to improve the wiki"), the agent calls a CLI script that performs graph analysis.
2. Based on the graph analysis results, the CLI script outputs, together with context, a path connecting the two most distant documents, and induces the AI agent to perform a specific task ([reverse dictionary search](https://wiki.g15e.com/en/pages/LLM%20as%20a%20reverse%20dictionary%20lookup%20algorithm.txt)).
3. The AI agent performs the concrete task as induced by the CLI's output.

In this case as well, recursive inversion of control has occurred.

## Generalization

If we generalize the two cases, we can see the difference between ordinary agent-tool interaction and the way recursive inversion of control occurs.

The only difference is whether the tool called by the agent merely plays the passive role of providing information, or whether it plays the role of strongly inducing a specific action by the agent (and thus, functionally, is equivalent to calling the agent). If the former is "Neuro-symbolic IoC," then the latter could be called "Recursive neuro-symbolic IoC."

It is a pattern in which the agent controls whether to call the tool, the called tool performs the kind of work the agent is not good at, and then the tool once again instructs the agent to do the kind of work the tool is not good at, thereby triggering the agent's work. At this point, the agent in turn carries out the work by calling other tools again (e.g. `git diff`, `grep`, [MCP](https://wiki.g15e.com/pages/Model%20context%20protocol.txt) servers, etc.), so it is recursive.

Technically it is a very small difference, but I think it is a pattern with great practical value. It seems like one of the patterns that can be used in various ways to [combine in a complementary way](https://wiki.g15e.com/pages/Beneficially%20relating%20elements.txt) traditional tools with deterministic characteristics and [LLM](https://wiki.g15e.com/pages/Large%20language%20model.txt)-based AI agents, which are a kind of probabilistic generative model.